We’ll look at some specific advice for/when working with initializing, proxy, oracles and auditing during the development of smart contracts on Solidity as we continue our series of educational articles!
Auditor’s Advice: Math, Solidity & Gas Optimizations | Part 1/3
Auditor’s Advice: Solidity Checklist & Reentrancy Attack | Part 2/3
Auditor’s Advice: EVM Limitations & Assembly Auditing Tips | Part 3/3
Additionally, today marks the continuation of a special series in which we will talk about various aspects of an auditor’s (or developer’s, if we’re talking about internal auditing) job. We promise it will be entertaining!
By the way, there are some vacant slots now so if your project needs an audit — feel free to write to us, visit our public reports page here. Let’s get in touch: gm@pessimistic.io!
Audits are essential for catching potential security risks and preventing potential exploits that malicious actors might leverage. They provide an extra layer of assurance by identifying flaws that might have been overlooked during development!
Any error or logical flaw in the code can result in unexpected behavior or vulnerabilities that can be exploited… So that, auditors examine the smart contract for any logical flaws, inconsistencies in business logic, or unintended consequences of specific contract actions. By identifying and rectifying logic errors during the auditing process, we can ensure that the smart contract functions exactly as intended before it is deployed.
By conducting an audit, we can ensure that the contract has been developed with secure coding practices, such as protection against potential attacks like reentrancy, arithmetic overflows, unauthorized access and so on. Auditors review the code from a security perspective, identifying potential weaknesses and suggesting improvements to prevent any potential exploits.
In recent months we have been actively developing our own Slither detectors (check out our Slitherin tool) to help with code review and audit process. Please let us know if you have discovered an issue/bug/vulnerability via our custom Slither detectors. You may contact us via opening a PR/Issue or directly, whichever is more convenient for you!
Since 2016, our team has accumulated a considerable number of observations, which we will provide here, along with numerous security advice. We can confidently say that such tips can be read publicly in a few places, and our blog is one of those places. The following will be our observations — only dry facts for auditors, tricks and the best life-hacks shared by our best auditors.
Everything you see below is based on our personal experience. And today, dear readers, it will be made available to you!
We finished our own research a few months ago; please read it if you haven’t already:
You will also find a list of tools and research for self-study, and we strongly recommend that you read it separately for better understanding! Let’s get started!
Nobody can deny that the foundation of any secure integration is a unique approach to code writing. As a result, this article will concentrate solely on those areas that might be quite valuable in keeping your code safe and secure.
Source: Smart Contract Upgradeability on the Ethereum Blockchain Platform: An Exploratory Study
Our team has gathered a sizable number of observations since 2016, which we will present here along with numerous security recommendations. You can significantly improve the integration of your project’s security by utilizing the techniques listed below:
initialize() can be called only once;
You should always check that the contract logic cannot be deleted (Parity Multisig). To do this (from the attacker’s perspective), you need to be able to jump to selfdestruct or delegatecall at a spoofed (fake) address. An unprotected initialize() often helps this issue to happen — from the attacker’s perspective, it probably hasn’t been called yet for the logic contract itself, so you can become its owner, or set the address for delegatecall, or something like that;
If the function accepts ether, then both the “proxy” and “logic” functions must be payable;
Contract-logic cannot rely on local storage because it is executed in the context of the calling contract (proxy). If the logic includes variables, they must either be initialized in the proxy (via initialize or setters), or they are immutable variables defined when the logic is deployed;
Always check out if/when the proxy calls target.initialize() during the deploy — that’s a correct way to do so;
You should carefully check out the storage layout in storage-proxy (Storage contract with full description of data structure, from which both logic and proxy inherit):
A) Storage layout should not change on upgrade (i.e. no deleting/inserting fields, resizing variables, etc.);
B ) `Logic is Storage` must not be extended by inheriting standard contracts: `Logic is Ownable, Storage` breaks the layout immediately, and `Logic is Storage, Ownable` prevents Storage from being augmented in the future;
We understand and respect your limited time, therefore we created a specific cheat sheet with nothing superfluous only for you! Check it out:
Pre-EIP155 factory with Create (not Create2) allowed to ‘seize’ addresses of projects on another chain;
“MoonBeam” — Chainlink shows the cost of assets on the native network (e.g. Mainnet). If a bridge (or token wrapper) is hijacked/hacked on that network, its value can diverge from Chainlink’s data. This can break protocols on that network that rely on oracle data;
We also finished our own research a few months ago; please read it if you haven’t already:
Implementing the recommendations outlined below can greatly enhance the security of your integration:
It is necessary to check that decimals of tokens are correctly taken into account in the code;
In all arithmetic operations with prices, check “dimensionality”;
In price oracles, one cannot only focus on the value calculated from the number of tokens on the contract balance at the current moment in time. We should also use TWAP with a longer time interval (description);
Source: A Study of Blockchain Oracles
When working with token wrappers (c-tokens, y-tokens) remember that native currency wrappers (cETH) have no underlying token. For example, this should be taken into account in functions like getUnderlyingPrice() and getUnderlyingAddress(). Vulnerability example;
We also finished our own research a few months ago; please read it if you haven’t already:
Looking at this month’s never-ending hacks, one may wonder why they happen so frequently…
Have audit firms actually gotten worse at what they do???
By the way, here are some vacant slots in the second quarter of 2023 now so if your project needs an audit — feel free to write to us, visit our public reports page here!
This, in our opinion, is not the case; yet, the topic is rather tricky because, in certain ways, you can reduce the risks to yourself and your project!
Check out our Pessimistic’s Spotter On-Chain Monitoring & Active Protection Service! Unlike the private version, the public version (this channel) reveals attacks selectively and does not allow you to track a specific address!
But first, I’d really like to ask you to read our previous article from which you can learn about the history of Spotter and the progress of development. Please subscribe to our blog to make sure you don’t miss any of the regular news and updates we plan to publish on the project in a special digest:
Risk mitigation is not something to set and forget; it’s a continuous process of monitoring, updating, and refining processes based on evolving market conditions. So, we updated the Spotter Telegram Bot to the public version. We made the onboarding and the customization as easy as possible, so you are able to set up alerts in 5 minutes!
Try it for free: @attackdetectorbot
You can configure the alerts using a Telegram bot, and then use the /genkey command to get the API key. Based on the signals from API, you can then set up any defense action:
We at pessimistic sincerely hope you find our work useful and appreciate any feedback, so please do not hesitate to contact us! The best answers and questions may be included in the next blog post. We hope that this article was informative and useful for you!
By the way, several audits have been completed successfully! By the way, here are some vacant slots now so if your project needs an audit — feel free to write to us, visit our public reports page here!
Support is very important to me, with it I can do what I love — educating users!
If you want to support my work, please, consider donating me:
0xB25C5E8fA1E53eEb9bE3421C59F6A66B786ED77A or officercia.eth — ETH, BSC, Polygon, Optimism, Zk, Fantom, etc
4AhpUrDtfVSWZMJcRMJkZoPwDSdVG6puYBE3ajQABQo6T533cVvx5vJRc5fX7sktJe67mXu1CcDmr7orn1CrGrqsT3ptfds — Monero XMR