_Follow along with this video:_ --- Re-entrancy is a big deal! So, how do we fix this? There are a few ways, the easiest of which is adhere to the CEI pattern. ### CEI Pattern _What's a CEI pattern?_ I'm glad you asked! CEI stands for Checks, Effects and Interactions and is a best practice for orders of operation. 1. Checks - require statements, conditions 2. Effects - this is where you update the state of the contract 3. Interactions - any interaction with external contracts/addresses come last Let's look at this in the context of our `withdrawBalance` example. ```js function withdrawBalance() public { // Checks /*None*/ //Effects uint256 balance = userBalance[msg.sender]; userBalance[msg.sender] = 0; //Interactions (bool success,) = msg.sender.call{value: balance}(""); if (!success) { revert(); } } ``` Our function has no checks, but simply by reordering things this way, with our effects before interactions, we're guarded against re-entrancy. We can confirm this in [**Remix**](https://remix.ethereum.org/#url=https://github.com/Cyfrin/sc-exploits-minimized/blob/main/src/reentrancy/Reentrancy.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.20+commit.a1b79de6.js). ### Remix Confirmation First, let's make sure we've re-ordered things in our contract.  Now fund your victim contract and try calling the `attack` function with a second wallet address, as we did before.  It reverts! So, what's happening here?  ### Alternative Mitigation There is another popular way we can protect from re-entrancy and that's through a locking mechanism we could apply to this function. This is also very simple to implement and would look something like this: ```js bool locked = false; function withdrawBalance() public { if(locked){ revert; } locked = true; // Checks // Effects uint256 balance = userBalance[msg.sender]; userBalance[msg.sender] = 0; // Interactions (bool success,) = msg.sender.call{value: balance}(""); if (!success) { revert(); } locked = false; } ``` This is called a `mutex lock` in computing science. By applying the above logic, we lock the function once it's called so that it can't be re-entered while locked! Along this line we also have the [**OpenZeppelin ReentrancyGuard**](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol) library available to us. This effectively applies locks to our functions under the hood keeping our code clean and professional by leveraging the `nonReentrant` modifier. ### Wrap Up That's it! We've learnt 3 simple ways to protect against re-entrancy vulnerabilities in our code. 1. Following CEI - Checks, Effects, Interactions Patterns 2. Implementing a locking mechanism to our function 3. Leveraging existing libraries from trust sources like [**OpenZeppelin's ReentrancyGuard**](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol) For such an easy vulnerability to protect against, re-entrancy continues to significantly impact the Web3 ecosystem. Let's take a specific look at how in the next lesson.
Follow along with this video:
Re-entrancy is a big deal! So, how do we fix this?
There are a few ways, the easiest of which is adhere to the CEI pattern.
What's a CEI pattern?
I'm glad you asked!
CEI stands for Checks, Effects and Interactions and is a best practice for orders of operation.
Checks - require statements, conditions
Effects - this is where you update the state of the contract
Interactions - any interaction with external contracts/addresses come last
Let's look at this in the context of our withdrawBalance
example.
Our function has no checks, but simply by reordering things this way, with our effects before interactions, we're guarded against re-entrancy. We can confirm this in Remix.
First, let's make sure we've re-ordered things in our contract.
Now fund your victim contract and try calling the attack
function with a second wallet address, as we did before.
It reverts! So, what's happening here?
There is another popular way we can protect from re-entrancy and that's through a locking mechanism we could apply to this function.
This is also very simple to implement and would look something like this:
This is called a mutex lock
in computing science. By applying the above logic, we lock the function once it's called so that it can't be re-entered while locked!
Along this line we also have the OpenZeppelin ReentrancyGuard library available to us. This effectively applies locks to our functions under the hood keeping our code clean and professional by leveraging the nonReentrant
modifier.
That's it! We've learnt 3 simple ways to protect against re-entrancy vulnerabilities in our code.
Following CEI - Checks, Effects, Interactions Patterns
Implementing a locking mechanism to our function
Leveraging existing libraries from trust sources like OpenZeppelin's ReentrancyGuard
For such an easy vulnerability to protect against, re-entrancy continues to significantly impact the Web3 ecosystem. Let's take a specific look at how in the next lesson.
Fixing Re-Entrancy in Smart Contracts:CEI Pattern, Lock Variables & Non-Reentrant Modifier
Previous lesson
Previous
Next lesson
Next
Give us feedback
Duration: 25min
Duration: 1h 18min
Duration: 35min
Duration: 2h 28min
Duration: 5h 03min
Duration: 5h 22min
Duration: 4h 33min
Duration: 2h 01min
Duration: 1h 40min