This article was written by Boro and Uri, Mighty Block blockchain developers, You will find in it the path to becoming a Smart Contract Developer!
Stepping into the digital realm’s dynamic frontier, where innovation intertwines with decentralization, is the path of a smart contract developer. In a world shifting from Web 2.0 to Web 3.0, our role has gained unprecedented prominence. Imagine writing code that represents unalterable agreements and cutting out intermediaries – that’s the magic of smart contracts. This article is your gateway to understanding what it takes to become a master of this blockchain-powered craft. From unraveling the intricacies of different programming languages to illuminating the deployment process on diverse blockchain platforms, we’ll embark on a journey that unveils the profound evolution from lines of code to immutable digital contracts.
What is a smart contract?
At its core, a smart contract is a decentralized digital agreement that runs on a blockchain. Picture a traditional contract – one that outlines the terms and conditions of a transaction or agreement – but now imagine this contract being automated, enforced, and executed without the need for intermediaries. This is where smart contracts shine. Structurally, a smart contract is composed of code that defines the rules, logic, and conditions of an agreement. Think of it as a virtual ‘if-then’ statement: if certain pre-defined conditions are met, then the contract executes a specific set of actions. This structure ensures that transactions are tamper-proof, transparent, and irreversible once they’re executed on the blockchain.
Why web3
In the evolution of the internet, we’ve moved from the static websites of Web 1.0 to the interactive platforms of Web 2.0. The transition to Web 2.0 brought us social media, online collaboration, and user-generated content, all centralized on platforms owned by big tech companies. However, the model came with drawbacks. User data privacy concerns and the centralized control of information became apparent as platforms monetized user data and exercised content moderation power. This sets the stage for Web 3.0, a decentralized paradigm shift. Web 3.0 leverages blockchain technology to distribute control, data ownership, and transactions across a network of participants. This means that users have more ownership over their data and identities, and transactions are executed in a transparent and secure manner without intermediaries. As data breaches, content censorship, and privacy issues continue to plague the digital landscape, the move towards Web 3.0 gains momentum. Its emphasis on user empowerment, privacy, and open protocols is driving innovation, with the potential to redefine how we interact online, from social networking to financial transactions.
Main smart contract structure
Let’s say we want to create an ERC20, the MightyBlockCoin that goes by the ticker MBC, our contract should keep track of MBC wallet balances, allow to transfer between wallets, amongst other functionalities. This is what the structure of such a contract would look like:
- Constructor: This piece of code is executed before the deployment is finished and typically sets some initial data on the storage of the contract. Since this code is only executed on deployment, it is used and tossed, it’s not actually stored on the chain.
For MightyBlockCoin we want to limit wallets to a maximum of 10 MBC per transfer. Our constructor will set maxTransferAmount to 10. - Storage definition: These are your persisting variables, where you will keep useful information for the usage of the contract. You have the well-known integers, strings and bools and also complex data structures that go by “structs” on Solidity, but the most useful ones are mappings that basically work as non-iterable dictionaries with very fast access by key.
Our ERC20 will need to keep track of balances, for such purpose there will be a mapping(address => uint256) this means a dictionary where the wallet addresses are the keys and their balances are the values, we also need to store the maxTransferAmount that we set on the constructor. - View methods: Not all transactions are made equal, view methods are designed to allow the user to access a piece of information without the need to modify the storage-state, incurring no gas cost. You can try to restrict access to view methods, but it’s generally a bad practice to do so and the barrier is easily avoidable by skilled inquirers.
In our example, we would have a getBalance method where walletAddress is the parameter and we return the MBC balance of such wallet. - Storage-modifying methods: The backbone of a smart contract, it’s the ways that storage is allowed to mutate, this methods include security, access, consistency and permission checks. If and when all those pass then the storage altering actions are performed.
The transfer function for MBC validates that the sender has enough balance and the transfer amount is lower (or equal) than maxTransferAmount. Lastly it stores the new balances for both the sender and the receiver. - Events: Transactions on the blockchain do not provide any response other than the fact that it executed. To keep some type of log of what happened, we emit personalized events that are defined on the contract. Events come with a name and parameters, they are the basic tool that most platforms use to keep track of what’s going on.
For an MBC transfer we would want a Transfer event with parameters sender, receiver and transfer amount.
EVM vs NO EVM + testing
Venturing further into the realm of smart contract development, it’s crucial to grasp the landscape of blockchain ecosystems and programming languages that power them. Blockchain platforms can be broadly categorized into those that utilize the Ethereum Virtual Machine (EVM) and those that don’t. EVM-based blockchains, like Ethereum itself, offer a standardized execution environment for smart contracts, ensuring consistency across different nodes. On the other hand, non-EVM blockchains, such as Algorand and Solana, employ their own unique execution environments optimized for specific purposes.
When it comes to programming languages for a smart contract developer, Solidity stands tall as the primary choice for Ethereum-based contracts. It’s a statically-typed language specifically designed for smart contracts. Vyper is another language for Ethereum that focuses on security and simplicity, making it a preferred option for scenarios where code clarity is paramount. Beyond Ethereum, Rust has gained attention for its use in the Solana blockchain due to its efficiency and safety features.
But programming languages are just one piece of the puzzle. Testing and development environments play a crucial role in ensuring the reliability of smart contracts. Tools like Hardhat, a JavaScript-based development environment, and Brownie, its Python counterpart, provide testing, deployment and debugging capabilities. They enable developers to simulate blockchain environments locally, helping to catch errors and security vulnerabilities before deployment. These tools offer sophisticated testing frameworks and integration with popular testing libraries, enabling developers to write comprehensive test suites to ensure contract functionality and security.
Navigating the landscape for smart contract developer involves understanding the nuances of EVM and non-EVM blockchains, choosing the right programming language for the job, and utilizing robust testing frameworks. As the ecosystem evolves, developers need to stay adaptable, continually learning and adapting their skills to keep up with the dynamic world of blockchain technology.
New challenges in web3
Testing
Our experience with testing Solidity has been quite challenging, for our particular use case and technology stack, we decided that Python + Brownie suited us best. The reality of the matter is that Brownie emulates a real environment locally, this means that smart contracts have to be deployed in order for transactions to be sent against them. Given that you can only interact with the public/external methods the ability of creating unit tests is limited, as internal or private methods cannot be called.
Deployment
Deploying smart contracts can be even more challenging than testing. Usually developers and owners are different people, this means that a developer might not have access to the private key, which in turn means that someone else, following the dev’s lead, has to send the transaction with the owner wallet.
Since smart contracts are immutable by design, each deployment is a big deal, for that reason we work to ensure that the experience is secure, smooth and seamless as there are no rollbacks. In practical terms, for every deployment that we schedule, we plan ahead and create a checklist with the step by step guide of what to do, which commands to run and in what given order.
Security
The mix of the monetary value stored inside a contract and the immutability of it, makes it crucial to think about security ahead since rules cannot be changed on the fly. On top of that, every transaction is independent, there is no such thing as a session, it must check all possible scenarios every time to ensure that only the intended usage is the allowed usage. Any exploits left in the open, are entry points for hackers and malicious actors, and even when the issue is detected, it can’t be fixed since the contract cannot be altered.
Technical limitations of Solidity
There are no floating point numbers, this leads to using integers to store numbers with decimal places, making it sometimes confusing to know the number’s scale. Another impractical limitation is Solidity’s inability to keep complex data structures in storage, requiring the developer to find a workaround to store the data in a more complex but Solidity-friendly way. Thirdly, an arch enemy of the developer is Solidity’s impossibility to handle dynamic size arrays, for example when searching all elements that meet certain condition, the data must be looped through once to determine the array’s size and then one extra time to populate said array with the matching elements. Last in this list but definitely not least is the infamous “stack too deep” error, which appears when too many variables are being used in the context of one given function, forcing workarounds to remove variables or reorganize code into separate smaller functions until the error is gone.
Liveops
Once the contract has been deployed, all types of issues may arise, the blockchain scanner, blockchain query tools amongst other, are essential tools to master to be able to handle such scenarios. This usually entails following transactions around and reading logs/events until the root cause unravels.
Paradigm shifts
It’s quite common to encounter accesibility modifiers on functions such as public and private when working on a Web 2.0 project. In Solidity, 2 other visibilities must be taken into account including external and internal, security concerns of each option should be considered when using them. The next big paradigm shift comes in the form of storage types, storage is used in situations where memory isn’t best suited and viceversa, mastering the usage of storage types is essential as they are mandatory for most variable declarations. Finally, units are stored in different scales, most values might need some multiplication or division by 10**18 to account for the difference between wei and eth values.
External resources
Managing third party information requires workarounds as there are no APIs you can call or external resources you can access easily, calling other contracts requires you to store their address and importing their interface in order to interact with them. The challenge of getting external information becomes substantial and oracles come to fill that void. Oracles are paid services that offer on-chain information that is not easily accesible otherwise, they represent to web3 what public APIs do for web2.
Language caveats
How would you sort an array of elements in Java? Well, you would simply call Array.sort(), that’s not an option in Solidity. Usually builtin methods entail a trade-off between performance and readability. Solidity is not willing to trade performance off, since performance is gas and gas is money. There are options like OpenZeppelin, which provides a library of frequently used methods to make the code more readable while still performing best practices. Nonetheless, implementing the methods for this basic operations still tends to be the best option. Other missing methods in Solidity are: min, max, filter, removeAt, foreach, etc.
Conclusions from a smart contract developer
As we conclude this epic journey through the realm of a smart contract developer, it’s evident that the digital landscape is undergoing a transformation unlike any other. The shift from Web 2.0 to Web 3.0 signifies a pivotal moment where decentralization, security, and user empowerment take center stage.
In the world of smart contracts, we’ve delved deep into their structure, the intricate web of challenges and opportunities that await the intrepid developer. Testing and deployment have proved to be crucibles where code is refined, ensuring the reliability of smart contracts. Security remains paramount, as every line of code written in the blockchain is etched in history, unalterable by design. Technical limitations and paradigm shifts have been embraced as challenges, not obstacles, by the developers pioneering this new era.
In this brave new world, we’ve witnessed the rise of oracles, the intricacies of storage types, and the relentless pursuit of performance. The absence of built-in methods has sparked creativity, making the Solidity developer a master of their craft.
Through it all, we’ve come to realize that Web 3.0 is not just a technological shift; it’s a philosophical one. It champions the ideals of decentralization, data sovereignty, and transparency. As the blockchain ecosystem continues to evolve, adaptability and continuous learning become the armor of the smart contract developer.
So, fellow adventurers in the digital realm, take these learnings with you as you embark on your journey into the ever-expanding universe of smart contracts. From the humble lines of code to the immutable contracts etched in the blockchain, you are the architects of a decentralized future, where trust is forged in code and the magic of Web 3.0 becomes a reality.
As the digital frontier beckons, remember, you are the pioneers, the masters of blockchain’s arcane arts, and the guardians of a more equitable and decentralized digital world. The future awaits your code.
We are always looking for Web3 talent !
Mighty Block is one of the partners of Forte, a platform to enable game publishers to easily integrate blockchain technologies into their games. We believe blockchain will enable new economic and creative opportunities for gamers around the world and have assembled a team of proven veterans from across the industry (Kabam, Unity, GarageGames, ngmoco, Twitch, Disney), as well as a $100M developer fund & $725M funding, to help make it happen. That’s where you come into play.
Feel free to browse all our current open job opportunities in the following link 👇