The Security Benefits of Monad
In the past 3 years, over four billion dollars of assets have been lost due to on-chain exploits; these losses serve as one of the largest deterrents to the mainstream adoption of decentralized apps. A major contributor to this problem is that implementing security measures in smart contracts on Ethereum is expensive. In the battle to minimize gas costs for users, Ethereum developers frequently feel pressure to forego additional safety checks.
Examples of gas optimizations include:
Limiting the use of defensive assertions and only including code essential for app functionality. Defensive assertions are essential to preserving invariants, especially as code gets upgraded.
Using counterintuitive tricks that save gas at the cost of readability. Tricks like making any function payable, using mappings in place of arrays, and avoiding libraries make code harder to understand and increase the probability of errors during upgrades.
Using shortcuts that minimize on-chain interaction, when a more interactive design might have offered better security properties. For example, the original ERC-20 design was that users would approve an app for a specific amount of tokens, but in practice, most frontends request infinite approvals, in part to avoid repeated gas expenditures for users.
With roughly 250 billion dollars of value secured on Ethereum in ERC-20s and NFTs, the stakes for contract security are exceptionally high. In Monad, we substantially reduce the cost of gas, rendering most current gas optimizations unnecessary, and allowing developers to focus on building the best version of their apps.
Background: Ethereum’s Gas Model
In Ethereum, each opcode costs a certain number of compute units, aka gas. The more computation, the more gas consumed. When users call a function on a smart contract, they pay for the gas consumed by the opcodes in that function.
Since computational resources on Ethereum are extremely limited, every operation is quite expensive. Reducing the number of operations while still preserving functionality is thus important in lowering user costs. These optimizations take a few forms, each of which comes with its pitfalls.
Defensive assertions are valuable
Experienced developers include defensive assertions to guard against unexpected scenarios. Like the name sounds, a defensive assertion is a way of codifying an expectation that should always be true. For example, if an internal variable is always expected to be nonnegative, then the programmer could write require(var >= 0, 'encountered negative var') and know that if this is ever not true, the transaction will revert. This defends against hacks which leverage unexpected scenarios.
Many of the biggest exploits in DeFi are re-entrancy attacks. In a re-entrancy attack, a smart contract gets into an unexpected state, usually after being called recursively by a cleverly-constructed contract that exploits some logical bug. Core to a re-entrancy attack is the fact that the contract gets into a bad state but doesn’t realize it. “Realizing it” would be achieved using defensive assertions.
Even beyond re-entrancy avoidance, defensive assertions help avoid the occasional bonehead mistake. For example, it is a common mistake to send tokens to the wrapped Ether (WETH) contract, where they become permanently stuck. There are frequent discussions to add additional checks that block this, but these checks would cost more gas, which is worse for non-erroneous users.
Over a million dollars in assets have been lost on the WETH contract alone due to the lack of these safeguards.
Micro-optimizations reduce legibility
There are a variety of weird tricks that save gas, arguably at the cost of legibility. Here are a few examples:
Marking a function as ‘payable’ (even if it’s not intended as such) reduces gas:
Usage of assembly:
Avoiding use of external libraries:
More weird tips:
Legibility improves understanding which improves security. Teammates and auditors need to easily understand code so they can look for vulnerabilities as well as avoid bugs when making later modifications.
Safe practices exist for a reason
In some cases, we see developers explicitly choosing unsafe practices for the sake of gas efficiency.
ERC-20 approvals are a good example. The original ERC-20 spec called for users to approve an app for a specific amount of tokens, so that the app can only spend the expected amount. But in practice, most frontends request infinite approvals, in part to avoid repeated gas expenditures for users. If the app’s deployer is compromised, attackers can drain funds directly from the wallets of users who gave these permissions.
As another example, Solidity provides SafeMath, which checks for overflow and underflow. A popular ‘tip’ is to disable these safety checks in order to save some gas:
Safe practices exist for a reason, but in the current state of Ethereum there’s an incentive to circumvent these practices.
What Needs to Change
Due to the high cost of computation, app developers currently make a tradeoff between security and cost. The path of least resistance for apps that are both safe and cheap to use is the drastic reduction of computation costs. Removing the need for developers to cut corners when writing code is a simple yet overlooked aspect of app security that is not overlooked at Monad.
Monad is creating a no-compromise environment for developers. The path to onboarding the next billion users will require apps that are both safe and usable; there is no better place to build these than on Monad.