B004: Smart Contract Centralization
In the blockchain space, the term “decentralization” has been hashed over again and again leading to it deviating from its true meaning as well as purpose. We will showcase certain paradigms we have seen commonly applied in projects that surrender an unwarranted amount of control to the project’s original deployer and how to avoid them.
A contract’s ownership can be expressed in multiple ways, be it via using a standard implementation such as
Ownable by OpenZeppelin, a more elaborate scheme such as
AccessControl again by OZ or even coding one’s own implementation from scratch.
Many smart contract systems today contain functions that allow fine-tuning of their parameters and as such, these functions should be privileged as they can lead to system misbehavior. Rendering the functions privileged, however, does not necessarily mean a single authoritative party should be in control of their execution.
The example above is one of many that are especially prevalent in new and coming projects that are usually unjustified, given that minting an arbitrary amount of tokens to an arbitrary member should not be a function readily available by an ERC20 token meant to acquire sensible value, even more so privileged questionably to the owners of the project.
A quasi-decentralized solution to contract ownership is to utilize a multi-signature wallet implementation as the “owner” of the contracts. Although this may appear as a solution, it is meaningless if the parties involved in the multi-signature process are unknown given that a multi-signature is as trustworthy as the collusion resistance of its members.
A true solution to contract ownership is to utilize a DAO implementation as the “owner” of the contracts. With a properly configured governance eligibility and voting power mechanism, a privileged function’s execution will be directly commanded by the community.
Although a utopian solution, a big drawback of the DAO system is that its resilience directly correlates to its adoption and if adoption is low, it is relatively simple for one to maliciously influence the DAO’s action by amassing sufficient voting power over a period of time, as seen in the True Seigniorage Dollar “hack”.
To avoid these types of incidents from arising, a dynamic system should be put in place similar to Compound’s governance system whereby certain authoritative actions are held by a “guardian” that is then phased out of the system completely as the system’s adoption matures.
Smart contracts are immutable pieces of code that execute in a deterministic manner regardless of their hardware & environment. As such, it is entirely possible to strictly dictate the expected logic paths the code is meant to execute and prohibit otherwise “unwanted” execution paths from occurring.
In the example above, the denominator of the
fee variable which the result of multiplying a value with
fee will be divided by is equal to
1000, however, no input sanitization is performed on the
setFee function. The only argument against sanitizing the input
_fee would be the contract’s bytecode size, an argument that should be deemed invalid if the maximum bytecode limit is not breached.
Although the above snippet is relatively straightforward in its effects, I have personally observed more questionable patterns emerging, such as not applying the Checks-Effects-Interactions pattern in functions that perform actions on the project owner’s account.
Although the above snippet is paraphrased, one can deduce that it would be easily possible for the project’s owners to cause a re-entrancy and siphon more funds than they should out of the contract. Good faith and blind trust in the human element is something that should not be considered by smart contract code; the code itself should precisely dictate what execution paths should be possible in its system.
This is a relatively self-explanatory issue that can be observed in both recent as well as historical projects. Minting the total supply of a token directly to the contract’s deployer used to be an accepted pattern but over time it has progressed into a tool for rug-pulls to quickly dump and destroy their token’s value for a quick profit.
Thankfully patterns such as bonding curves, liquidity generation events, and in general forms of token collateralization have been devised and are being applied quite more frequently as of late, ensuring that the tokens that would be purchased do have an inherent value that is separate from their speculative value.
Another more obscure way for protocol owners to “centralize” the project’s output to themselves is to render the system’s mechanics unfairly weighted in their favor. As a prime example, SafeMoon and its forks contain a unique LP recirculation mechanism that accrues fees to re-deposit liquidity in the token’s BNB pool.
A caveat of this functionality is that all LP tokens minted via this method are directly assigned to the owners of the project who are free to do as they wish. Thus, the captured value of the re-circulation concept is held by the project owners in its entirety.
The same pattern could have been applied with the final owner of the LP tokens being either a DAO-based account or the burn address directly, thus cementing the project’s decentralization and not relying on the good behavior of a single party/affiliation.
Decentralization is a fluid term that can vary in degree depending on the actual needs of a project, however, it is easy to discern which projects do not boast this trait even to the slightest degree. Every potential investor and user of a project should perform their own due diligence in the decentralization of it as it is a safe indicator of both its health and maturity.