5/5 - (1 vote)

Smart contracts are small, immutable pieces of code that run on the Ethereum blockchain. Once deployed, they cannot be updated. You cannot patch a bug or fix a security flaw later. That’s why checking for smart contract vulnerabilities before Ethereum contract deployment is crucial.

A common mistake developers make is using the wrong visibility modifiers. These small keywords can create significant risks if misused.

In this guide, we focus on a practical example rather than abstract theory. You will:

  • Build a Content Access Contract
  • Test it for issues
  • Spot problems caused by incorrect Solidity visibility modifiers

This article is perfect for anyone with intermediate Solidity skills. A basic understanding of Remix IDE, Ganache, and core Ethereum development will help.

We will work on a Solidity Smart Contract that manages access to course content, showing you exactly how to secure your contract while avoiding common pitfalls.

Building a Content Access Contract

In this Solidity tutorial, we will build a Solidity Smart Contract to manage access to hackathon course materials. We’ll use Remix IDE as the development environment and Ganache to simulate the blockchain locally.

This contract lets learners pay a fee with their crypto wallets. After payment, they receive a unique authorization code to access course content.

The goal is to create a Web3 development platform. Learners register using crypto wallet authentication. Once the fee is paid, the contract generates a random 9-digit authorization code. This code acts as a key to unlock the course materials. The materials themselves remain off-chain. The smart contract only interacts with the Ethereum blockchain to verify payments. This makes the system fast, secure, and cost-effective.

The Content Access Contract stores all authorization codes along with the Ethereum wallet addresses that own them. When a learner tries to access the course, the platform checks the blockchain-based backend for a matching code. If it finds one, the learner is granted access.

This setup combines smart contracts, web3 payment systems, and a blockchain-based backend to build a secure, decentralized course platform.

Following this hands-on example, you will learn smart contract security, understand Solidity visibility modifiers, and see how a Solidity Smart Contract handles payments, authentication, and access control. This practical workflow mirrors real-world blockchain and decentralized course platforms, giving you experience building secure, functional Ethereum smart contracts.

To build the content access contract using Remix IDE:

image

  • Just open your browser and jump into the Remix IDE.
  • On the far left, locate the Icon Bar.
  • Click the File Explorer icon.
  • Right-click the contracts folder.
  • Select New File from the menu.
  • Name the file contentaccess.sol. A new tab with this name will appear in the editor.
  • Paste the following code into the editor to start building your contract.

 

Image from reference

 

The first line of our Solidity smart contract declares the MIT license. This line matters because machine-readable licenses help other developers understand how to use your code. It also supports open-source blockchain development.

Right after that, we set the Solidity version. This tells the compiler how to read and handle the code. Then we add NatSpec comments. NatSpec stands for Ethereum Natural Language Specification Format, a comment style that helps explain your contract in plain language. These comments clearly demonstrate the contract, its functions, and return values. They help anyone reading the contract understand what each part does.

Arrays and Mappings

The contract begins with a unit array named collectionOfAuthCodes. This array stores all the authorization codes generated for the course platform. Arrays work well when you want to keep a list of similar data in order.

Next, we introduce several mapping variables. Mappings work like key–value stores, helping the contract look up information quickly.

Here’s what each mapping does:

  • authCodeOwner shows who owns each authorization code.
  • authCodeOfLearner returns the authorization code for a specific Ethereum wallet.
  • Both mappings are marked as public, so Solidity automatically creates getter functions for them.

We also have authCodeCount. This mapping tracks how many times a wallet has called the createAuthCode function. This helps stop misuse and improves smart contract security.

Setting the Price in Wei

The authCodePrice variable stores the fee for generating an authorization code. The value is in wei, which is the smallest unit of Ether. Ethereum uses wei, gwei, and Ether.

We use Wei because it gives accurate pricing and works smoothly with the setAuthCodePrice() function. In the example, 2^18 wei equals 2 ETH. This amount is high for testing, but it helps us clearly track payment behaviour.

A real fee is usually 0.1-0.2 ETH. Since Ethereum does not support decimals, using wei simplifies calculations. For example, 0.2 ETH becomes 2^17 wei.

Why This Setup Matters

This setup makes the smart contract simple, secure, and ready for real testing. By using arrays, mappings, and wei-based pricing, we follow Solidity best practices. These choices also support Web3 payment flows, Ethereum smart contract design, and secure access systems for blockchain-based course platforms.

With explicit visibility modifiers, structured data, and safe value handling, this contract serves as a strong example of innovative, secure Solidity contract development. It prepares you for real-world Web3 apps, decentralized learning platforms, and modern blockchain education tools.

The following line is an event statement that will be called at the end of the addAuthCode() function. In Solidity, event statements act as signals that let the frontend know when the blockchain state updates. You declare a Solidity event as follows: 

Following the event statement is a list of function declarations. You declare functions as follows:

The first public function, setAuthCodePrice(), takes a uint parameter and updates the authCodePrice variable, which represents the fee for creating an authorization code.

The following three functions work together to create authorization codes. The generateAuthCode() function generates a 9-digit authorization code by applying the Ethereum keccak256 hash function to the result and casting the result to a uint. A hash function takes an input and returns a seemingly random 256-bit hexadecimal number. Even a slight change in the input will completely change the hash output. To use keccak256 correctly, you must pack the parameters into a single bytes type before calling the function. For example:

Given that a hash function in Ethereum always generates the same hash for the same input, two different callers could receive identical authorization codes if they enter the same input. To prevent this, we pass Solidity special variables as additional arguments to the keccak256 Solidity function.

In our generateAuthCode function, we pass a single parameter along with msg. Sender Solidity and block. Timestamp Solidity. Msg. Sender refers to the address calling the function, while block refers to the address of the function itself. Timestamp provides the current blockchain time. This ensures each authorization code is unique.

The addAuthCode function takes the code generated by generateAuthCode, adds it to the array, and assigns the authCodeOwner mapping to the caller. This associates each authorization code with a specific Ethereum wallet.

The createAuthCode payable function collects a fee from users or contracts each time an authorization code is generated. Its first statement ensures that there is one execution per account. The second statement debits the caller and credits the contract. It then calls the generateAuthCode and addAuthCode functions.

The getNumberOfLearners function returns the total number of learners with an authorization code. The withdraw function in Solidity transfers the contract’s stored funds to the caller. The getCollectionOfAuthCodes function returns all authorization codes.

This implementation is essential for smart contracts, a content access contract, a blockchain hackathon platform, and a secure blockchain-based backend.

It provides practical experience in smart contract security, understanding smart contract vulnerabilities, and applying Solidity coding guide principles to build a Solidity smart contract.

Compiling and Deploying a Smart Contract

The EVM (Ethereum Virtual Machine) can only read and execute EVM bytecode. After completing the previous tutorial, you need to compile your Solidity smart contract to generate bytecodes. These bytecodes are sent as a deployment transaction to the Ethereum network and interpreted by the EVM. A transaction is a request to execute a smart contract, and contracts run only when an external account function call triggers them.

Compiling a Smart Contract Using Remix IDE

To compile your contract:
image

  1.     Go to the Icon Bar.
  2.     Click the Solidity compiler icon. The side-panel will update with configuration options.
  3.     Click the large blue Compile button with your contract’s name.

Deploying a Smart Contract Using Remix IDE

Before deployment, install the blockchain simulator Ganache to test smart contracts.

To deploy:
image

  1.     Launch Ganache.
  2.     Click the Deploy & Run Transactions icon.
  3.     Configure your deployment. Select Ganache as the blockchain and set Ethereum accounts.
  4.     Click Deploy. The terminal shows the transaction details, and the selected account is debited.
  1.     Scroll down and expand the deployed contract to access auto-generated function buttons.

This ensures your Ethereum smart contracts are tested and deployed safely on a Web3 development environment.

Finding the Vulnerability in Our Content Access Contract

Once you build a Solidity smart contract, auditing it is crucial. Start by testing its public and external functions. These functions are exposed to the blockchain so that anyone can interact with your contract.

Our test focuses on the security of our content access contract.

Test Cases

 ID: TC_01

Title: Check authorization code creation using the createAuthCode() payable function

Steps:

  1.     Select Ether under the value field.
  2.     Enter the code creation fee (2 ETH).
  3.     Pass an input as an argument to createAuthCode().

Result: A new authorization code smart contract is generated for the caller. The caller’s account is debited, while the contract’s account is credited with the fee.

ID: TC_02

Title: Check authorization code creation using the addAuthCode() function

Steps:

  • Pass integer digits to addAuthCode() and call it.
  • Click on getCollectionOfAuthCodes().

Result: Another authorization code is created. But the caller’s account is not debited, and the contract remains unchanged.

After these tests, one account holds two codes. Check the authCodeOwner and authCodeOfLearner mappings. These are public and auto-generated by the compiler.

The behaviour is unusual. Each address should have only one code. Also, user accounts should be debited, and the contract credited.

Why This Happens

The contract has three functions for generating authorization codes. Two are helper functions.

If exposed, they bypass checks in the createAuthCode() payable function, which ensures the caller has funds and no existing code.

Since addAuthCode() is public, a hacker can manually input numbers. They can assign ownership to msg. Sender and insert fake codes. One address ends up with multiple codes, breaking the blockchain course access system.

How to Fix This

Use private visibility modifiers for helper functions. This prevents direct access.

Some functions must remain public or external:

  • Withdraw () function solidity: Withdraws funds. Exposing it risks theft.
  • setAuthCodePrice(): Changes fees. Malicious users could inflate it.
  • getNumberOflearners() & getCollectionOfAuthCodes(): Return statistics. Only the owner should call.

Proper visibility modifiers and Solidity improve smart contract security, but they have limits.

Conclusion

Visibility modifiers are critical in smart contract security. Wrong modifiers create vulnerabilities and financial risks.

Applying solidity visibility modifiers correctly ensures your Solidity smart contract works as intended, keeps dApps safe, and protects your blockchain hackathon platform.

Explorer
Remix IDE
smart contracts
Web3 development
Protocloud Technologies - CEO

Ajay Shah

I'm Ajay Shah, co-founder of Protocloud Technologies, an IT consulting firm. I stay updated with the latest tech trends and share insights with my audience. My focus areas include eCommerce, Healthcare, Real Estate, ERP, Education, Sports, Gaming, and Travel. if you’re curious about what’s trending in these industries, I’ve got you covered!