Smart contract gas griefing attack | The hidden danger
To be able to perform the different tasks and execute the operations in its source code, smart contracts require a certain level of gas. This gas is paid by the ...
secure coding + Smart contract + Solidity + Blockchain Security + How to + blog Z. Oualid today
Making an audit against a smart contract is a great thing. However, finding vulnerabilities without fixing them is useless. Unfortunately, smart contracts are immutable by design, which means that once the smart contract is deployed, it cannot be changed. So how to fix a smart contract?
To fix a vulnerable smart contract you should follow the next steps:
Proxies are only one of the possible techniques to fix a smart contract. Here is the list of the different techniques that can be used to fix a smart contract once it gets deployed:
In this blog post, we are going to mainly focus on the last two techniques as they are the more practical and most popular. You are going to see in detail and step by step what should be put in place to be able to upgrade and fix your smart contract once it gets deployed in the Blockchain.
This blog post will contain both technical and theoretical concepts to better understand the way smart contracts could be updated. In addition, I am going to give you as many examples as possible to get an idea about what your code may look like in the future. Moreover, you will see both the automatic and manual ways of deploying a proxy.
So if you are interested, please just keep reading and do not hesitate to leave a question below and I will do my best to respond.
To fix a smart contract, you should first make it upgradable. Therefore, to make a smart contract upgradable a proxy should be put in place.
In this section, I will give you the most recommended and easy way of deploying upgradable smart contracts. All you have to do is to follow this section step by step and do not jump any word on it and you will be able to make any smart contract updatable. In addition, I will give you two ways of doing things, one manually by using Openzeppelin smart contracts in case you are working only with remix, and the second one is by using Hardhat.
To implement a proxy for your smart contract manually all you have to do is to:
The idea is that the proxy will be the interface seen by the users and its address is the one that will be distributed to the users. In addition, the proxy will be responsible for saving all the smart contract stat. However, all the business logic will be stored in the other smart contract that you will be able to upgrade whenever you want.
Here is the step-by-step process to put in place a proxy for your smart contract:
To be able to modify your smart contract in the future, you should first prepare it to do so. Therefore, here are some key elements that your smart contract code should satisfy to be able to use proxies and upgrade them in the future:
Here is a small example of such contract:
The initialize() function can be used to replace the constructor to be able to initialize some variables in the deployment phase. This is used because constructors are not allowed while working with proxies. The reason behind this restriction is that, if the contract has a constructor, then once it is deployed it will initialize the contract stat and not the proxies variables which are the ones clients interact with and change.
In addition, initializers are executed only once. This also means that this function will only be executed during the first deployment of the contract and the proxy. After that, the initializer function could not be called once again to reinitialize variables with different values even after deploying a new version of the contract.
Once the smart contract you want to upgrade in the future is well prepared, then you can now deploy it.
Deploying a proxy is very easy with the Openzeppelin library. All you have to do is to download and deploy the TransparentUpgradeableProxy smart contract proxy. You can find this smart contract here:
@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol
To upgrade your smart contract all you should do is:
And you will be able to communicate with the new contract with the same old address.
When using Hardhat you have two options to automate the process of deploying a proxy. The first one is using the hardhat built-in plugin, or using the Openzeppelin plugin. In this blog post, we are going to use the Openzeppelin plugin.
To be able to use this plugin you should:
In your hardhat.config.js file include the following line:
require('@openzeppelin/hardhat-upgrades');
If the Openzeppelin plugin is not yet imported into your project you can use the following command:
Yarn hardhat add –dev @openzeppelin/hardhat-upgrades
To do this please take a look at the step 1 of the manual technique.
In your scripts folder, create a new JS file and add the following source code:
const { ethers, upgrades } = require("hardhat");
async function main() {
const contractv1= await ethers.getContractFactory("contractv1");
const proxy = await upgrades.deployProxy(contractv1, [param1, param2]);
await proxy.deployed();
console.log(proxy.address);
}
main();
This code simply deploys your smart contract “contractv1” that takes 2 parameters param1 and param2 for its initializer function. Then deploy the proxy and connect it to your contract. Those three steps are all made by calling deployProxy() function.
Once your smart contract proxy is deployed, upgrading to newer versions could be done using the following line of code:
const { ethers, upgrades } = require("hardhat");
const proxyAddress = "";
async function main() {
const contractv2 = await ethers.getContractFactory("contractv2");
const upgraded = await upgrades.upgradeProxy(proxyAddress, contractv2);
console.log((await upgraded.function1()).toString()); //test
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
proxyAddress is the address of the smart contract proxy.
Social migration simply means deploying a whole new smart contract, migrating all the old smart contract stat to the new one, and then trying to convince the community to switch to it. This technique is efficient in terms of fixing the smart contract and adding more features.
However, it is complicated to first migrate all the stats of the old contract to the new one. In addition, it is not easy to convince the community that uses your smart contract to switch to the new one. Moreover, this technique is both time-consuming and may cost developers so much money to put in place.
Also, finding a critical vulnerability could happen just after you deploy your update, and it is not possible to perform a new update 1 day after convincing the community to switch.
With all these limitations, this technique could be feasible for smaller communities and may work better for them. In some cases, using this technique would be even more efficient than the others.
Changing the smart contract parameters is another way of updating or upgrading a smart contract. Upgrading a smart does not simply add or fix code, it could be as simple as changing a parameter in the smart contract to remove a business loss.
This technique usually does not require much time and money to deploy. However, this technique is very limited in terms of what can be fixed and will usually not be enough to fix discovered vulnerabilities.
The technique of upgrading smart contracts using proxies is based on the idea of creating an unchangeable smart contract that holds all the smart contract stats and uses delegatedcalls to execute the business logic stored in another contract. Using this technique the users will have one smart contract address to communicate with no matter what update the developers do.
Deploying a proxy for a smart contract is the most popular technique for upgrading a smart contract due to its efficiency to fix complex vulnerabilities and bugs without even changing the actual address of the smart contract. However, this technique also suffers from some limitations that should be worked around.
In this section, we are going to explain in detail, the most popular smart contract proxy standards and the idea that each one of them tries to implement and why.
Deploying a smart contract proxy comes with some technical problems related to how EVM works. One of the most popular problems that could lead to some serious security issues is the function clashes.
This problem happens when either two functions with whole different signatures have the same first 4bytes, or when the admin of the proxy calls a function that exists in both the proxy contract and the logic contract. In this situation, the EVM will execute the proxy function. Therefore, both the admin and the client will never be able to reach the function in the business logic contract.
The transparent proxy standard was introduced to solve this problem by making a separation between calls that came from the proxy admin and those that come from a user. The idea here is that every transaction that comes from the proxy admin will trigger functions held in the proxy contract and reject the other calls. In addition, the calls that came from simple users will be directly forwarded to the business logic contract even if it matches one of the proxy contract functions.
By implementing this concept the risk of having those confuses is reduced. However, another problem arises. The fact that all the proxy admin calls are matched to the proxy contract only, then if the admin tries to communicate with the logic contract, all his transactions will be reverted. However, this problem could easily be solved, by creating a dedicated admin account that can even be a smart contract, which is what the Openzeppelin plugin exactly does.
Globally UUPS and transparent proxies have the same functionalities in terms of delegating calls and the proxy core that they inherit from. However, the main difference between them is the fact that transparent proxies are upgradable by default. This means that they hold the upgradability functions in their source code, which makes them more expensive. Contrarily to the transparent proxies, UUPS proxies give the logic holding smart contract the obligation to handle the upgradability by implementing a function that changes the UUPS proxy data slot that holds the business logic contract address. Here is an image that better describe these two concepts:
Both proxies still exist in the Openzeppelin repository. However, Openzeppelin recommends switching the UUPS proxy. For more details about these two concepts take a look at the following link.
The last technique we are going to discuss in this blog post is the CREATE2 technique to upgrade a contract. The name of this technique comes from the EVM opcode CREATE2 which was introduced in February 2019.
The CREATE opcode allows developers to deploy smart contract in the Blockchain and return the address where it was generated. The address is generated using the following:
new_address = hash(sender, nonce)
Unlike the CREATE opcode, the CREATE2 allows developers to specify where exactly they want to deploy their smart contract (at which address). More details about this opcode could be found here.
Using the CREATE2 opcode instead of the CREATE introduces so many abilities to the developers. One of those abilities is to upgrade the smart contract without changing its address.
The idea behind this technique is to call the self-destruct function in the contract you want to upgrade then use the same address to deploy the new one using the CREATE2 opcode.
The contract that was deployed suing CREATE2 and holds a self-destruction function are called metamorphic contracts. This type of contract solves the issue of upgradability and vulnerability patching in a smart contract but also introduces a whole new danger.
Imagine that after investing your money in a protocol, the next day you wake up you check the smart contract address you sent your money to it, and you discover that all the source codes have changed. Moreover, you discover that the admin has now the ability to drain all your money anytime he wants and that you simply cannot withdraw back your coins.
Therefore, I highly do not recommend using this technique for both the danger that it represents for users and the contract itself that uses the self-destruction function. In addition, this technique can be used in honeypots to steal users funds.
If you want to know more about the kind of vulnerabilities that you can fix in a smart contract I highly recommend taking a look at the following blog posts:
Written by: Z. Oualid
I am a Cyber Security Expert, I have worked with many companies around the globe to secure their applications and their networks. I am certified OSCP and OSCE which are the most recognized and hard technical certifications in the industry of cybersecurity. I am also a Certifed Ethical hacker (CEH). I hope you enjoy my articles :).
blog Z. Oualid
To be able to perform the different tasks and execute the operations in its source code, smart contracts require a certain level of gas. This gas is paid by the ...
Copyright © 2020 Getsecureworld.
Post comments (0)