0% found this document useful (0 votes)
28 views1 page

Unit 5 - Solidity Basics Part 1

This document provides a comprehensive overview of various Solidity programming concepts, including array management, constructors, inheritance, contract interactions, error handling, enums, access control, events, and function types. Each section includes code examples and key concepts that highlight the functionality and best practices in Solidity smart contracts. The document serves as a practical guide for developers looking to implement these features in their own smart contracts.

Uploaded by

Shubham Yadav
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
28 views1 page

Unit 5 - Solidity Basics Part 1

This document provides a comprehensive overview of various Solidity programming concepts, including array management, constructors, inheritance, contract interactions, error handling, enums, access control, events, and function types. Each section includes code examples and key concepts that highlight the functionality and best practices in Solidity smart contracts. The document serves as a practical guide for developers looking to implement these features in their own smart contracts.

Uploaded by

Shubham Yadav
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1

1.

sol

Solidity Array Management in Smart Contracts

In this Solidity example, we explore how to manage arrays within a smart contract.

1. Declaring Arrays:

arr_1 : A dynamic array of unsigned integers ( uint256[] ), initially empty.


arr_2 : Another dynamic array, initialized with three values [3, 2, 4] .
arr_3 : A fixed-size array of 5 uint256 elements, but uninitialized.

2. Getting Value from an Array:


The getValueOfIndex function allows the user to retrieve an element from arr_2 at a specific
index.

Task: Add a check to ensure the index is within the array’s bounds to avoid errors.

Example of adding a check:

require(_index < arr_2.length, "Index out of bounds");

3. Adding to the Array:


The addToArray function demonstrates how to dynamically add elements to arr_2 using the
push() method. This method appends a new value to the end of the array.

Improvements:

Always validate array indices when accessing elements.


Dynamic arrays allow for easy appending but remember that fixed-size arrays (like arr_3 ) don’t
support push() .

2.sol

Constructors and Inheritance in Solidity

In this example, we’re exploring how to use constructors and inheritance in Solidity.

1. Constructor in MyConstructor Contract:

The constructor is a special function that runs once when the contract is deployed. It initializes
the state variable name with the value passed during deployment.

constructor(string memory _name) {


name = _name;
}

2. Creating Getter and Setter Functions:


To access and modify the name variable, we’ll create getter and setter functions.

Getter: Returns the current value of name .

function getName() public view returns (string memory) {


return name;
}

Setter: Allows the contract owner to update the name .

function setName(string memory _newName) public {


name = _newName;
}

3. Inheritance in MySecondContract :
The MySecondContract inherits from MyConstructor . It calls the parent contract’s constructor to
initialize the name variable using the MyConstructor(_name) syntax.

The constructor in MySecondContract simply passes the provided _name to the parent
MyConstructor 's constructor.

constructor(string memory _name) MyConstructor(_name) {}

Final Code

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract MyConstructor {

string public name;

constructor(string memory _name) {


name = _name;
}

// Getter function for 'name'


function getName() public view returns (string memory) {
return name;
}

// Setter function for 'name'


function setName(string memory _newName) public {
name = _newName;
}
}

contract MySecondContract is MyConstructor {


constructor(string memory _name) MyConstructor(_name) {}
}

Key Concepts:

Constructors: Initialize state variables when the contract is deployed.


Inheritance: MySecondContract inherits MyConstructor , reusing its functionality.
Encapsulation: The getter and setter allow controlled access and modification of the name variable.

3.sol

Interacting Between Contracts in Solidity

This Solidity example demonstrates how one contract can interact with another by calling its functions.

1. Contract MyOtherContract :

This contract contains a public state variable age , initialized to 29 .


It also has a function getAge() that returns the value of age .

uint256 public age = 29;

function getAge() public view returns (uint256) {


return age;
}

2. Contract CONTRACTB :

The getAgeFromOtherContract function allows CONTRACTB to interact with another contract


( MyOtherContract ) by using its address.
We pass the address of the MyOtherContract instance, cast it as MyOtherContract , and call
its getAge() function.

Key steps:

Use the contract’s address ( _contractAddress ) to interact with its public functions.
The function getAgeFromOtherContract retrieves the age from the other contract.

function getAgeFromOtherContract(address _contractAddess) public view returns (uint256


MyOtherContract other = MyOtherContract(_contractAddess);
uint256 age = other.getAge();
return age;
}

Key Concepts:

Contract Interaction: In Solidity, one contract can call another contract’s public functions by
referencing its address and creating an instance.
Casting: MyOtherContract(_contractAddress) casts the provided address to a type of the
MyOtherContract so that you can call its functions.

Example Use Case:

If you deploy MyOtherContract and pass its address to CONTRACTB , the latter can fetch the age value
from MyOtherContract and return it.

4.sol

Errors, Checks, and Conditions in Solidity

In this Solidity example, we will learn how to use require , revert , and assert to handle errors and add
necessary checks to a contract. Additionally, we’ll implement a time-based restriction for a function.

1. Require Statement:

The require function ensures that certain conditions are met before the execution of the
function proceeds.
In myFunc , we check if _x is smaller than _y . If not, an error message "X is bigger than Y"
is thrown.

require(_x < _y, "X is bigger that Y");

2. Revert:

The revert function is used to explicitly abort a function when a certain condition is met.
In myPureRevertFunc , if _x == 10 , the transaction will revert with the message "X is 10" .

if(_x == 10) {
revert("X is 10");
}

3. Assert:

The assert function is used to test for conditions that should never fail.
In checkMax , we ensure that maxAmount is always 100 . If it is not, the contract will halt
execution with an error.

assert(maxAmount == 100);

4. Adding a Timestamp Check:

We can add a time-based check using Solidity’s block.timestamp to restrict function calls to
within 2 days of a particular event.
For this example, we will modify myFunc to ensure it can only be called within a 2-day window
after the contract deployment (or after a certain point).

Here’s how you can add the check in myFunc :

uint256 public startTime;

constructor() {
startTime = block.timestamp;
}

function myFunc(uint256 _x, uint256 _y) public view returns (uint256 xy) {
require(block.timestamp <= startTime + 2 days, "Function can only be called within
require(_x < _y, "X is bigger than Y");
checkMax();
return _x + _y;
}

startTime stores the block timestamp when the contract is deployed.


The require(block.timestamp <= startTime + 2 days) ensures that myFunc can only be
called within 2 days after the contract is deployed.

Final Code Example

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract MyErrorsAndChecks {
uint256 public maxAmount = 100;
uint256 public startTime;

constructor() {
startTime = block.timestamp;
}

function updateMax() public {


maxAmount = 50;
}

function myFunc(uint256 _x, uint256 _y) public view returns (uint256 xy) {
// Allow calling only within 2 days from contract deployment
require(block.timestamp <= startTime + 2 days, "Function can only be called within 2
require(_x < _y, "X is bigger than Y");
checkMax();
return _x + _y;
}

function myPureRevertFunc(uint256 _x, uint256 _y) public pure returns (uint256 xy) {
if(_x == 10) {
revert("X is 10");
}
return _x + _y;
}

function checkMax() internal view {


assert(maxAmount == 100);
}
}

Key Concepts:

require is used for input validation and ensuring certain conditions are met.
revert allows you to abort a transaction explicitly when certain logic fails.
assert is for internal invariants that should never fail.
Time-based checks can be performed using block.timestamp for limiting function usage within a
specified period.

5.sol

Enums, Access Control, and Function Updates in Solidity

In this Solidity example, we use an enum to represent different levels of rarity and implement access
control to allow only an admin to update the rarity. We’ll also modify the function to accept a parameter for
setting any rarity and add a getter function to retrieve the current rarity without access control.

Key Features:

1. Enum Definition:

enum Rarity { original, rare, super_rare } : Defines three types of rarity.


Each type has an underlying index, starting from 0 for original , 1 for rare , and 2 for
super_rare .

2. Access Control:

We’ll restrict the makeSuperRare (or any function that updates rarity) to be callable only by the
admin. For simplicity, we’ll define the contract deployer as the admin.

3. Update to Accept Rarity Type:

Instead of hardcoding the rarity update to super_rare , we’ll modify the function to accept any
Rarity type as a parameter.

4. Get Function:

A simple getter function will return the current rarity value.

Code Implementation:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract MyEnums {

// Define an enum with 3 rarity types


enum Rarity {
original, // 0
rare, // 1
super_rare // 2
}

Rarity public rarity; // State variable to store the current rarity

address public admin; // Variable to store the admin address

// Constructor sets the initial rarity and defines the admin as the contract deployer
constructor() {
rarity = Rarity.rare; // Default to rare
admin = msg.sender; // Set contract deployer as admin
}

// Function to allow admin to update the rarity to any type


function makeSuperRare(Rarity _rarity) public {
require(msg.sender == admin, "Only admin can update rarity");
rarity = _rarity;
}

// Getter function to retrieve the current rarity without any access check
function getCurrentRarity() public view returns (Rarity) {
return rarity;
}
}

Breakdown:

1. Admin Access Control:

The require(msg.sender == admin) ensures that only the address that deployed the contract
(the admin) can call the makeSuperRare function.

2. Function to Set Any Rarity:

makeSuperRare now accepts a parameter of type Rarity :

function makeSuperRare(Rarity _rarity) public {


require(msg.sender == admin, "Only admin can update rarity");
rarity = _rarity;
}

This allows the admin to update the rarity to any value from the Rarity enum (either
original , rare , or super_rare ).

3. Getter for Rarity:

The getCurrentRarity function returns the current value of rarity without any checks.

function getCurrentRarity() public view returns (Rarity) {


return rarity;
}

Key Concepts:

Enums allow you to define a set of named constants. They are particularly useful for defining specific
states or options like rarity levels.
Access Control ensures that certain functions are only executable by authorized parties (in this case,
the admin).
Function Parameters: The function now accepts a parameter, allowing flexibility when setting the
rarity instead of hardcoding specific changes.

6.sol

Events in Solidity: Emitting Logs

In this Solidity example, we explore how to use events to log important contract actions on the blockchain.

1. Event Declaration:

event CreatedNFT(address indexed user, uint256 id, uint256 dna); defines an event
that records the address of the user who created the NFT, along with its ID and DNA.
The indexed keyword allows us to filter logs by the user address, making it easier to search for
specific events.

2. Emitting the Event:

Inside the createNft function, the event CreatedNFT is emitted. This generates a log on the
blockchain when the function is called.
The msg.sender represents the address of the caller (the user creating the NFT).

Code Example:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract MyEvents {

// Declare the event with indexed user


event CreatedNFT(address indexed user, uint256 id, uint256 dna);

// Function to create an NFT and emit the event


function createNft(uint256 _id, uint256 _dna) public {
// In real-world scenario, NFT creation logic would go here

// Emit the event to log the creation


emit CreatedNFT(msg.sender, _id, _dna);
}

Key Concepts:

1. Events:

Events allow you to write logs to the blockchain, which are stored but not accessible on-chain
by smart contracts. They are primarily used to communicate information from the blockchain to
external applications like DApps.

2. Indexed Parameters:

The indexed keyword allows the user address ( msg.sender ) to be searchable when querying
the logs. Only up to 3 parameters can be indexed in an event.

3. Emitting Events:

emit CreatedNFT(msg.sender, _id, _dna) broadcasts the event with the provided data,
which can be accessed by off-chain applications like web3 or any blockchain explorer.

Practical Use:

DApps can listen for the CreatedNFT event to update their user interface or backend whenever an
NFT is created, without having to constantly query the blockchain.

7.sol

Functions in Solidity: Types and Use Cases

This Solidity example demonstrates various types of functions in a smart contract, including pure, view,
internal, external, and functions that return values.

Key Components:

1. State Variables:

myUint , myString , myBool , and myArr are state variables stored on the blockchain.
These variables represent different types of data: uint256 , string , bool , and an array of
uint256 .

2. Pure Function:

A pure function doesn’t read or modify the contract’s state; it only performs computations
based on input parameters.
Example: myPureFunc adds two integers without accessing any contract variables.

function myPureFunc(uint256 _x, uint256 _y) public pure returns (uint256 xy) {
return _x + _y;
}

3. View Function:

A view function reads from the contract’s state but doesn’t modify it. In this example,
myViewFunc reads the value of myString but doesn’t change it.
This function is marked as internal , meaning it can only be called within the contract or by
derived contracts.

function myViewFunc() internal view returns (string memory) {


return myString;
}

4. State-Modification Function:

myUpdateFunc is a public function that updates the state variable myString and uses the
myViewFunc to return the updated value. This shows how internal functions can be called
within the same contract.

function myUpdateFunc() public returns (string memory) {


myString = "LPU";
string memory savedString = myViewFunc();
return savedString;
}

5. Function Returning Multiple Values:

myReturnsFunc is an external function that returns multiple state variables at once: myUint ,
myString , myBool , and myArr .

function myReturnsFunc() external view returns (uint256, string memory, bool, uint256[
return (myUint, myString, myBool, myArr);
}

6. Function with No Return:

myNoReturnFunc is an external function that simply updates the state variable myBool to
false without returning any value.

function myNoReturnFunc() external {


myBool = false;
}

Final Code Summary:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract MyFunctions {

uint256 myUint = 42;


string myString = "Piyush";
bool myBool = true;
uint256[] myArr = [3, 3, 3];

// Pure function - No state read/write


function myPureFunc(uint256 _x, uint256 _y) public pure returns (uint256 xy) {
return _x + _y;
}

// Internal view function - Reads state, no modification


function myViewFunc() internal view returns (string memory) {
return myString;
}

// Public function - Modifies state, calls internal view function


function myUpdateFunc() public returns (string memory) {
myString = "LPU";
string memory savedString = myViewFunc();
return savedString;
}

// External function - Returns multiple state variables


function myReturnsFunc() external view returns (uint256, string memory, bool, uint256[]
return (myUint, myString, myBool, myArr);
}

// External function - Modifies state, no return


function myNoReturnFunc() external {
myBool = false;
}
}

Key Concepts:

Pure Functions: Perform calculations without reading or modifying the contract’s state.
View Functions: Read the contract’s state without modifying it.
State-Modifying Functions: Functions that alter the state of the contract (e.g., updating variables).
Internal vs. External Functions: Internal functions are used within the contract, while external
functions are called from outside the contract.

8.sol

Simple if else

9.sol

Inheritance in Solidity with Function Overrides

In this Solidity example, we explore inheritance and function overriding. In Solidity, contracts can inherit
from other contracts, and child contracts can override parent functions.

Key Components:

1. Base Contract ( MyInheritance_A ):

The contract defines an internal state variable name set to "LPU" .


The internal keyword allows this variable to be accessible in derived contracts but not from
outside the contract itself.

2. Intermediate Contract ( MyInheritance_B ):

This contract inherits from MyInheritance_A and defines the getName function, which returns
the value of name .
The function is marked virtual , which allows it to be overridden by child contracts.

3. Derived Contract ( MyInheritance_C ):

Inherits from MyInheritance_B .


It overrides the getName function and returns a different value, "Daniel" .
The override keyword ensures that the function is recognized as an override.

Code Example:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// Base contract
contract MyInheritance_A {
string internal name = "LPU"; // Internal variable accessible in child contracts
}

// Intermediate contract inheriting from MyInheritance_A


contract MyInheritance_B is MyInheritance_A {

// Virtual function that can be overridden in derived contracts


function getName() public view virtual returns (string memory) {
return name; // Returns the inherited name "LPU"
}
}

// Derived contract inheriting from MyInheritance_B and overriding getName


contract MyInheritance_C is MyInheritance_B {

// Override the getName function to return a different value


function getName() public view virtual override returns (string memory) {
return "Daniel"; // Returns "Daniel" instead of "LPU"
}
}

Key Concepts:

1. Inheritance:

MyInheritance_B inherits from MyInheritance_A , and MyInheritance_C inherits from


MyInheritance_B . Each child contract has access to the parent’s state variables and functions.
Inheritance enables code reusability by allowing contracts to share functionality.

2. Function Overriding:

The getName function in MyInheritance_B is marked as virtual , allowing it to be overridden


in derived contracts.
In MyInheritance_C , the getName function is marked as override , which indicates that this
function replaces the parent’s implementation.

3. Internal Visibility:

The internal keyword used for the name variable ensures that it is accessible in derived
contracts ( MyInheritance_B and MyInheritance_C ) but not directly from outside the
contract.

Practical Use:

This inheritance structure allows contracts to share and modify behavior in child contracts, making
the code modular and easier to maintain. By overriding functions, you can customize behavior for
different child contracts.

10.sol

Interfaces in Solidity: Implementation Example

This Solidity example demonstrates how to implement an interface using the ICounter interface and the
MyInterface contract.

Key Concepts:

1. Interface Definition ( ICounter ):

An interface in Solidity is like a blueprint. It defines functions but does not provide their
implementation.
The ICounter interface has two functions:
count() : Returns the current counter value.
addToCount() : Increases the counter by 1.
Interfaces are used to enforce that contracts implementing them provide certain functionalities.

2. Contract Implementation ( MyInterface ):

The MyInterface contract implements the ICounter interface by providing concrete


implementations for count() and addToCount() .
The contract uses the keyword override to indicate that these functions are fulfilling the
interface’s requirements.
It maintains an internal counter variable to track the count.

Code Example:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// Interface declaration
interface ICounter {
function count() external view returns (uint256);
function addToCount() external;
}

// Contract implementing the interface


contract MyInterface is ICounter {

uint256 counter = 0; // State variable to store the count

// Override the count function to return the counter value


function count() external view override returns (uint256) {
return counter;
}

// Override the addToCount function to increment the counter


function addToCount() external override {
counter++;
}
}

Key Concepts:

1. Interfaces:

Interfaces define the functions that a contract must implement. They do not have state
variables or implementation details.
Functions in interfaces are automatically external and must be marked as override in the
implementing contract.

2. Implementing an Interface:

The contract MyInterface implements the ICounter interface by providing the actual logic
for both count() and addToCount() .
The count() function is marked view because it only reads the counter value.
The addToCount() function updates the state by incrementing counter .

3. Override Keyword:

When implementing functions from an interface, you must use the override keyword to
explicitly state that the function is fulfilling the interface’s definition.

Practical Use:

Interfaces allow contracts to interact with other contracts in a standardized way. By using interfaces,
you ensure that any contract implementing the interface will provide the expected functionality. This
is useful when integrating different smart contracts into a larger ecosystem.

You might also like