Building a Simple Fixed Deposit Application Using Solidity Smart Contracts
Last Updated :
23 Jul, 2025
Blockchain technology has revolutionized the way we handle financial transactions, and the world of decentralized finance (DeFi) is growing at an unprecedented rate. One of the most intriguing aspects of this financial evolution is the use of smart contracts, which are self-executing agreements with the power to automate and secure various financial services. In this exploration of blockchain and smart contract development, we dive into the creation of a minimalist fixed deposit application using Solidity. By the end of this journey, you'll not only understand the fundamental principles of smart contract programming but also witness the practical application of Solidity in building a secure and efficient fixed deposit system.
Simple Fixed Deposit ApplicationDesigning the Smart Contract
In the context of Ethereum, it's vital to understand the distinction between two types of accounts: Externally Owned Accounts (EOAs) and Smart Contracts.
- EOAs are controlled by private keys and represent individuals, whereas Smart Contracts are self-executing scripts deployed on the blockchain.
- This knowledge is crucial for effectively managing and interacting with accounts in the world of blockchain finance.
- The "LockedSavingsAccount" smart contract creates an analog of the traditional fixed deposit system by employing the principles of blockchain technology and smart contracts to offer users a secure and automated way to lock funds.
However, unlike most fixed deposit systems, no interest is guaranteed. That would be implemented in another contract.
Implementing the Smart Contract
Let's dive right in starting with the solidity smart contract code:
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract LockedSavingsAccount {
mapping(address => uint256) public balances;
mapping(address => uint256) public lockTimestamps;
address public owner;
// Events that will be emitted on changes.
event fundsLocked(uint256 amount,uint256 duration);
event withdrawal(uint256 amount);
event data(uint256 amount, uint256 duration);
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can call this function");
_;
}
function lockFunds(uint256 duration) public payable{
//duration in seconds
require(msg.value > 0, "You must deposit some ether");
require(duration > 0, "Lock duration must be greater than 0 seconds");
balances[msg.sender] += msg.value;
lockTimestamps[msg.sender] = block.timestamp + duration;
emit fundsLocked(balances[msg.sender],lockTimestamps[msg.sender]);
}
function withdraw() public {
require(block.timestamp >= lockTimestamps[msg.sender], "Funds are still locked");
require(balances[msg.sender] > 0, "You have no funds to withdraw");
uint256 amount = balances[msg.sender];
bool success = false;
(success, ) = payable(msg.sender).call{value: amount}("");
if (success) {
balances[msg.sender] = 0;
emit withdrawal(amount);
} else {
// Handle the transfer failure, e.g., revert or emit an error event.
revert("Withdrawal failed");
}
}
function getData() public view returns(uint256 balance,uint256 timeLeft){
balance=balances[msg.sender];
timeLeft=lockTimestamps[msg.sender];
}
function contractBalance() public view onlyOwner returns (uint256) {
return address(this).balance;
}
}
Headers and State Variables
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
Here,
1. // SPDX-License-Identifier: MIT: This is a comment that indicates the license under which the smart contract is distributed. In this case, it specifies the MIT License, which is an open-source license. The SPDX-License-Identifier is a standardized way to declare the license for a smart contract so that developers and users of the contract can understand the terms and conditions of its use
2. pragma solidity ^0.8.0: This line is a 'pragma directive.' Pragmas are instructions for the Solidity compiler (the program that compiles your Solidity code into bytecode for the Ethereum Virtual Machine). In this line:
3. The 'pragma solidity' statement declares that the code is written in Solidity, which is the programming language used for Ethereum smart contracts.
4. ^0.8.0 specifies the version of the Solidity compiler the code is written for. This means that the code is intended to be compiled using Solidity version 0.8.0 or any compatible higher version. The caret (^) symbol indicates that the code should work with compatible compiler versions greater than or equal to 0.8.0 but might not be compatible with older versions.
You can obtain more information on these details by clicking here. Take note of the contract declaration, named 'LockedSavingsAccount.'
Solidity
//state variables
mapping(address => uint256) public balances;
mapping(address => uint256) public lockTimestamps;
address public owner;
This line declares a public state variable named 'balances' as a 'mapping'. In Solidity, a 'mapping' is a key-value store, somewhat similar to dictionaries or associative arrays in other programming languages. In this case:
- 'address' is the primary data type, signifying that the balances are linked to Ethereum addresses. Ethereum addresses are 20-byte identifiers that represent accounts on the Ethereum blockchain.
- 'uint256' is the value type, which means that for each address, there's an associated unsigned integer (a 256-bit integer) representing the balance.
- The 'public' keyword (more on state variable mutability below) makes the 'balances' variable accessible from outside the smart contract, allowing other contracts and external applications to read the balances
Since this smart contract stores funds of addresses, it needs a way to identify the amount locked by each address. Pictorially, the mapping can be thought of as a table, like so:
'address'
| 'Uint256'
|
---|
0x9876543210FE...BA98765432
| 5000000
|
0xAbCdEf123...90ABCDEF1234
| 4783000020
|
...
| ...
|
mapping(address => uint256) public lockTimestamps;
This line declares another public state variable named 'lockTimestamps'. It is also a mapping with the same key-value structure as 'balances', associating addresses with timestamps represented as 'uint256' values. This mapping is utilized to store the duration for which a user wishes to lock their funds, expressed in seconds.
address public owner;
This line declares a public state variable named 'owner.' It's a single Ethereum address variable used to store the address of the owner or creator of the smart contract. In many smart contracts, the 'owner' variable is employed to restrict certain functions or operations, making them callable only by the owner. The 'public' visibility modifier enables external parties to read the 'owner' address.
Events and Constructor
Solidity
// Events that will be emitted on changes.
event fundsLocked(uint256 amount,uint256 duration);
event withdrawal(uint256 amount);
event data(uint256 amount, uint256 duration);
constructor() {
owner = msg.sender;
}
In your smart contract, events are essential for transparency and external interaction. They enable external parties, such as other contracts or web applications, to listen to and respond to specific actions or state changes within the contract. The data emitted through events can be valuable for tracking and auditing transactions and contract activities on the Ethereum blockchain.
'fundsLocked' Event:
This event is declared with the following signature: 'event fundsLocked(uint256 amount, uint256 duration);'. It is used to log and emit information when a user locks funds into their savings account.
Parameters:
- 'amount': A 'uint256' variable representing the amount of ether (crypto funds) that the user locked.
- 'duration': A 'uint256' variable representing the duration in seconds for locking the funds.
This event is typically emitted when the 'lockFunds' function (see below) is called, and funds are successfully locked. It provides a means for external observers to track and monitor the locking of funds by users.
The same applies to the 'withdrawal' Event, which is used to log and emit information about when a user successfully withdraws funds from their savings account, and the 'data' Event, which returns the amount locked in the contract and the associated duration using the parameters 'amount' and 'duration'. These events are all triggered by a function, as you'll see below.
constructor() { owner = msg.sender; }
The constructor function in your Solidity smart contract is a special function that is executed only once when the contract is deployed to the Ethereum blockchain. Its primary purpose is to perform the initial setup and configuration.
It sets the 'owner' state variable (previously declared above) to the address of the contract deployer ('msg. sender'). 'msg. sender' is a special global variable in Solidity that represents the address of the sender of the current transaction. In this context, it signifies the address of the individual or entity deploying the contract.
Why the Constructor is Important?
- Initialization: The constructor initializes the owner state variable with the address of the contract deployer. This ensures that the owner of the contract is set when the contract is created.
- Security: By setting the owner within the constructor, you establish a clear owner who has control over certain functions in the contract, such as checking the contract's balance. This is a common pattern used to provide access control and enhance the security of smart contracts.
- Ownership: The owner can be a specific Ethereum address, typically the person or entity deploying the contract. They have special privileges to manage and monitor the contract. This pattern is often used to restrict access to sensitive functions to the owner only.
Modifier and Functions
Solidity
modifier onlyOwner() {
require(msg.sender == owner, "Only the owner can call this function");
_;
}
- Modifiers can be used to change the behavior of functions in a declarative way. For example, you can use a modifier to automatically check a condition before executing the function.
- If any function has this declared 'onlyOwner' modifier attached to its declaration, this line of code checks if the Ethereum address of the person or entity calling the function ('msg. sender') matches the address stored in the 'owner' state variable.
- If they do not match, the 'require' statement will throw an exception, reverting the transaction and displaying the error message "Only the owner can call this function" (the 'onlyOwner' modifier is used in the 'contractBalance' function).
- In essence, a modifier enforces access control by requiring that only the owner can execute specific functions, preventing unintended or malicious actions that could be harmful to the contract or its users. This might not sound decentralized to a reader, and for sure it isn't, but with time it becomes clearer.
Solidity
function lockFunds(uint256 duration) public payable{
//duration in seconds
require(msg.value > 0, "You must deposit some ether");
require(duration > 0, "Lock duration must be greater than 0 seconds");
balances[msg.sender] += msg.value;
lockTimestamps[msg.sender] = block.timestamp + duration;
emit fundsLocked(balances[msg.sender],lockTimestamps[msg.sender]);
}
The logic here is simple: the function is called with a duration, which represents the amount of time the funds will be locked, measured in seconds. You don't need to worry about the argument for the amount sent by the address to the contract, as it is implicitly included in 'msg. sender', as you will see. The definition of the function accomplishes the following:
- It requires a non-zero value to be sent with the transaction.
- It requires the lock duration to be greater than 0 seconds.
- It updates the previously declared user's balance and lock timestamp under the address entry.
- It emits the 'fundsLocked' event by calling the 'fundsLocked' event declared earlier.
'block. timestamp' represents the current block timestamp as seconds since the Unix epoch, and it is added to the duration you provide.
If you note the use of 'public' and 'payable', 'public' means that the function can be called by anyone, and 'payable' means the function also expects that some Ether (the native cryptocurrency of the Ethereum blockchain) must be sent along with the function call. This is where 'msg. value' comes into play.
Solidity
function withdraw() public {
require(block.timestamp >= lockTimestamps[msg.sender], "Funds are still locked");
require(balances[msg.sender] > 0, "You have no funds to withdraw");
uint256 amount = balances[msg.sender];
bool success = false;
(success, ) = payable(msg.sender).call{value: amount}("");
if (success) {
balances[msg.sender] = 0;
emit withdrawal(amount);
} else {
// Handle the transfer failure, e.g., revert or emit an error event.
revert("Withdrawal failed");
}
}
The frontend calls this function to withdraw funds if the lock duration has elapsed by comparing 'block. timestamp' and the user’s unlock time 'lockTimestamps[msg. sender]'. Then, it checks whether the user has a balance greater than 0.
The function attempts to send the funds to the user and updates the balance if the transaction is successful. If successful, another event 'withdrawal' is emitted; otherwise, a 'revert' is triggered. The 'revert("Withdrawal failed")' aborts execution and reverts state changes, providing an explanatory string.
Solidity
function getData() public view returns(uint256 balance,uint256 timeLeft){
balance=balances[msg.sender];
timeLeft=lockTimestamps[msg.sender];
}
The 'getData' function provides a way for users to query their balance and the remaining lock time. There's a significant change here, which is explained as follows:
The function is marked as 'view', indicating that it does not modify the contract's state; it only reads the data. This is also the reason an event is not emitted. Furthermore, the function definition has no return statement because the values to be returned are already declared in the 'returns(uint256 balance, uint256 timeLeft)' declaration. The function definition simply assigns values to those variables.
The use of events in the 'lockFunds' and 'withdraw' functions, as well as the absence of events in the 'getData' function, align with their respective purposes. The 'lockFunds' and 'withdraw' functions emit an event to notify external parties about significant state changes, while the 'getData' function simply retrieves data without affecting the contract's state.
A contrary view
- If you use a return statement in the 'lockFunds' and 'withdraw' functions, it would cause the function to exit prematurely, and the remaining code within the function would not be executed. In this context, using return might lead to unexpected behavior, potentially preventing the intended logic from executing correctly.
- If you use events in the 'getData' function, you'll need to remove the 'view' keyword and be prepared to pay a gas fee when the function is called. This is because emitting events modify the state of a contract, and modifying states comes at a cost.
Solidity
function contractBalance() public view onlyOwner returns (uint256) {
return address(this).balance;
}
Here, the 'onlyOwner' modifier function we declared is put to use. The 'contractBalance' function is designed to allow the contract owner to check the amount of Ether held within the contract. This functionality is valuable for the contract owner to monitor the funds within the contract and can serve various purposes, including financial oversight and decision-making. The use of the 'onlyOwner' modifier ensures that only the owner has access to this balance information, with the statement in the 'onlyOwner' modifier (as declared above) running before the code in the 'contractBalance' function.
Deploying the Smart Contract
Deploying the "LockedSavingsAccount" smart contract is a crucial step in bringing our minimalist fixed deposit application to life. To conform properly to the scope of this article, let's focus on using the Hardhat development environment for a local deployment.
1. Setting Up Hardhat
- Ensure that Hardhat is installed by running `npm install --save-dev` hardhat in your project directory.
- Create a `hardhat.config.js` file in the root directory and configure it with the necessary parameters.
2. Writing Deployment Scripts
- Create a deployment script, for instance, `01_deploy_locked_savings_account.js` in the scripts folder.
- In this script, use the Hardhat deployment functions to deploy the smart contract.
JavaScript
// scripts/01_deploy_locked_savings_account.js
const { ethers } = require("hardhat");
async function main() {
const LockedSavingsAccount = await ethers.getContractFactory("LockedSavingsAccount");
const lockedSavingsAccount = await LockedSavingsAccount.deploy();
console.log("LockedSavingsAccount deployed to:", lockedSavingsAccount.address);
}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
3. Running the Deployment
- Execute the deployment script using 'npx hardhat run scripts/01_deploy_locked_savings_account.js'.
- Verify that the contract is deployed successfully, and note the contract address.
4. Interacting with the Deployed Contract
- Utilize tools like the Hardhat console or write additional scripts to interact with the deployed smart contract.
- Fund your Ethereum accounts with test ETH to simulate real transactions on the blockchain.
Conclusion
By following these steps, you'll have successfully deployed the "LockedSavingsAccount" smart contract locally, enabling further testing and interaction in a controlled environment.
Similar Reads
Solidity Tutorial Solidity tutorial is designed for those who want to learn Solidity programming language and for experienced Solidity developers looking to gain a deeper understanding of the language. The following Solidity tutorial explains the basic and advanced concepts of Solidity programming language and provid
6 min read
Solidity Basics
Introduction to SoliditySolidity is a brand-new programming language created by Ethereum which is the second-largest market of cryptocurrency by capitalization, released in the year 2015 and led by Christian Reitwiessner. Some key features of solidity are listed below: Solidity is a high-level programming language designed
5 min read
Setting Up Smart Contract Development EnvironmentA development environment is an environment in which all the resources and tools are available which are used to develop a program or software product. Here, an attempt to create a development environment that is a collection of the processes and tools that are used to develop smart contracts.There
5 min read
Solidity - Basic SyntaxSolidity is a programming language specifically designed for developing smart contracts on the Ethereum blockchain. It is a high-level, statically-typed language with syntax and features similar to those of JavaScript, C++, and Python. Solidity is used to write self-executing smart contracts that ca
5 min read
"Hello World" Smart Contract in Remix-IDEWhat do you mean by Smart Contract? Smart contracts are self-executing contracts. The term was coined by Nick in 1994. Smart contracts are very different from traditional software programs. They are immutable once deployed on the blockchain. It was because of Ethereum the term smart contract became
4 min read
Solidity - CommentsComments are an important aspect of programming as they help in providing clarity and understanding to the code. They allow developers to document the code and explain its purpose, making it easier for others to read and maintain the code. Solidity, being a programming language, also supports the us
4 min read
Solidity - TypesSolidity is a statically typed language, which implies that the type of each of the variables should be specified. Data types allow the compiler to check the correct usage of the variables. The declared types have some default values called Zero-State, for example for bool the default value is False
4 min read
Variable and Operators
Control Flow in Solidity
Reference & Mapping Types in Solidity
Solidity - StringsSolidity is syntactically similar to JavaScript, C++, and Python. So it uses similar language structures to those languages. Strings in Solidity is a data type used to represent/store a set of characters. Examples: "Hii" // Valid string "Hello World" // Valid string "2022" // Valid string In Solidi
3 min read
Solidity - ArraysArrays are data structures that store the fixed collection of elements of the same data types in which each and every element has a specific location called index. Instead of creating numerous individual variables of the same type, we just declare one array of the required size and store the element
6 min read
Solidity - Enums and StructsEnums are the way of creating user-defined data types, it is usually used to provide names for integral constants which makes the contract better for maintenance and reading. Enums restrict the variable with one of a few predefined values, these values of the enumerated list are called enums. Option
3 min read
Solidity - MappingsMapping in Solidity acts like a hash table or dictionary in any other language. These are used to store the data in the form of key-value pairs, a key can be any of the built-in data types but reference types are not allowed while the value can be of any type. Mappings are mostly used to associate t
4 min read
Solidity - ConversionsSolidity is a programming language that is used to write smart contracts for the Ethereum blockchain. One important concept in Solidity is conversions, which allow you to change the type of a variable or expression. The article focuses on discussing three types of conversions in Solidity. The follow
6 min read
Solidity - Ether UnitsIn the world of Ethereum smart contracts, understanding how Ether (ETH) and its subunits work is crucial. Solidity is the programming language used to write these smart contracts, and it interacts directly with Ether, the cryptocurrency of the Ethereum network. This article focuses on discussing Eth
7 min read
Solidity - Special VariablesThere exist special variables and functions in solidity which exist in the global namespace and are mainly used to provide information about the blockchain or utility functions. They are of two types: 1) Block and Transaction Properties: Block Transaction Properties block.coinbase (address payable)C
3 min read
Solidity - Style GuideSolidity is a computer programming language used to create Ethereum smart contracts. These contracts self-execute. The code and the agreements contained therein are enforced by the blockchain network. Solidity is a high-level language, meaning that it is designed to be human-readable and easy to wri
13 min read
Solidity Functions
Solidity - FunctionsA 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
4 min read
Solidity - Function ModifiersFunction 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 modi
8 min read
Solidity - View and Pure FunctionsThe 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 'v
2 min read
Solidity - Fall Back FunctionThe 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 E
3 min read
Solidity Function OverloadingFunction 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 occ
1 min read
Mathematical Operations in SoliditySolidity is a brand-new programming language created by the Ethereum which is the second-largest market of cryptocurrency by capitalization, released in the year 2015 led by Christian Reitwiessner. Ethereum is a decentralized open-source platform based on blockchain domain, used to run smart contrac
6 min read
Solidity Advanced
Solidity - Basics of ContractsSolidity 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 i
4 min read
Solidity - InheritanceInheritance 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
6 min read
Solidity - ConstructorsA 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
4 min read
Solidity - Abstract ContractAbstract 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 i
3 min read
Solidity - Basics of InterfaceInterfaces 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 inte
2 min read
Solidity - LibrariesLibraries 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
4 min read
Solidity - AssemblyAssembly or Assembler language indicates a low-level programming language that can be converted to machine code by using assembler. Assembly language is tied to either physical or a virtual machine as their implementation is an instruction set, and these instructions tell the CPU to do that fundamen
4 min read
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, w
2 min read
Solidity - Error HandlingSolidity 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 erro
6 min read
Top 50 Solidity Interview Questions and Answers Solidity is an object-oriented programming language used to implement smart contracts on blockchain platforms like Ethereum, which generates transaction records in the system. To excel in your journey toward top companies as a Solidity developer, you need to master some important Solidity Interview
15+ min read