Sign In Start Free Trial
Account

Add to playlist

Create a Playlist

Modal Close icon
You need to login to use this feature.
  • Book Overview & Buying  Building Full Stack DeFi Applications
  • Table Of Contents Toc
  • Feedback & Rating feedback
 Building Full Stack DeFi Applications

Building Full Stack DeFi Applications

By : Zhou
4.6 (5)
close
close
 Building Full Stack DeFi Applications

Building Full Stack DeFi Applications

4.6 (5)
By: Zhou

Overview of this book

Enter the world of Decentralized Finance (DeFi) with Building Full Stack DeFi Applications. Understand how this blockchain-based financial technology, designed to manage crypto assets, runs independently without centralized financial institutions like banks and brokerages, eliminating the fees that banks and other financial companies charge for using their services. This book will show you how DeFi solutions are built with smart contracts running on blockchains and how they allow users to gain and earn crypto assets based on the trust of the smart contracts. This book uncovers the inner workings of DeFi by guiding you through the mathematical foundations and teaching you how to build real-world DeFi products with Solidity and JavaScript. As you progress through the chapters, you’ll learn how to implement smart contracts of liquidity pools to trade cryptocurrencies and implement staking, including farming features that allow users to earn. You’ll also find out how to create asset pools that allow users to lend and borrow cryptocurrencies and generate interest. Additionally, you’ll discover how to use Web3 libraries to build the frontend of DeFi products. By the end of this book, you’ll will be well acquainted with popular tools, libraries, and design patterns for implementing a full-stack DeFi application with Web3 and Solidity.
Table of Contents (21 chapters)
close
close
1
Part 1: Introduction to DeFi Application Development
5
Part 2: Design and Implementation of a DeFi Application for Trading Cryptos
11
Part 3: Building a DeFi Application for Staking and Yield Farming
14
Part 4: Building a Crypto Loan App for Lending and Borrowing

Vulnerabilities of DeFi applications

DeFi is one of the innovative technologies that introduced new financial activities for people and potentially changed the existing financial infrastructure. In this section, we will focus on the vulnerabilities that may occur in DeFi applications, especially the applications we are going to build in this book since hackers can leverage the vulnerabilities of smart contracts to exploit the crypto assets from smart contracts and users' wallets. Figure 1.8 shows that the total value hacked for DeFi has been around $6 billion since mid-2016:

Figure 1.8 – DefiLlama – DeFi loss by month

Figure 1.8 – DefiLlama – DeFi loss by month

Fortunately, most of the vulnerabilities have solutions. We will discuss various causes of these vulnerabilities and best practices to prevent these issues in this section. Some knowledge of the Solidity programming language will help you understand the code snippets in this section, but it is not required for you to understand the principles.

Reentrancy

Reentrancy is one of the most destructive security attacks in smart contracts written with Solidity. A reentrancy attack occurs when a function makes an external call to another untrusted contract. Then, the untrusted contract makes a recursive call back to the original function in an attempt to drain funds.

For example, an attack smart contract could implement a fallback function that withdraws funds from a vulnerable smart contract. When the attack smart contract receives the fund, the fallback function will be called automatically, which makes recursive calls, at which point it will withdraw the fund again until the fund in the vulnerable smart contract is drained. Figure 1.9 demonstrates the sequence of actions to perform this attack:

Figure 1.9 – The workflow of a reentrancy attack

Figure 1.9 – The workflow of a reentrancy attack

To find the relevant code example and learn more about reentrancy attacks, please go to https://solidity-by-example.org/hacks/re-entrancy/.

To prevent a reentrancy attack, we will use ReentrancyGuard from the OpenZeppelin (https://www.openzeppelin.com/) library when building DeFi applications later in this book.

Self-destruct operation

In the early days of Ethereum, one of the earliest DAO projects lost $3.6 million worth of ETH due to a hack. What’s even worse is that the attack continued for days due to the immutability of the smart contract on the blockchain, so the developer could not add a function to take back the ETH from smart contracts or destroy the smart contract to prevent hacking. In 2016, Ethereum introduced the selfdestruct function to serve as an exit door for smart contracts in case of an attack. Here is an example of how to use the selfdestruct function:

contract SelfdestructExample {
  function killContract(address payable receiver) external {
    selfdestruct(receiver);
  }
}

This code snippet defines a smart contract called SelfdestructExample. A person can call the killContract function to destroy the smart contract, at which point all the ETH held by the smart contract will be transferred to receiver when selfdestruct is called.

The behavior of transferring ETH to a specific address could cause a side effect. Hackers can then use this side effect to forcefully send ETH from a self-destruct smart contract to another smart contract to make it vulnerable.

The example at https://solidity-by-example.org/hacks/self-destruct/ shows the act of forcefully transferring ETH to a smart contract to break the rules of the game. There is a game that only allows players to transfer 1 ETH at a time. The person can win when the balance of the smart contract is equal to or greater than 7 ETH, and the winner can take all the ETHs. Although the game smart contract only allows a player to transfer 1 ETH every time, the attacker broke the rule by forcibly transferring more ETHs to the game smart contract in one transaction with the selfdestruct function.

The solution is using a storage variable in the smart contract to store the balance instead of using address(current_contract).balance. This will be the source of truth for the smart contract to rely on, and the selfdestruct function cannot manipulate the variable.

Gas overflow

All the transactions that need to write data on the blockchain need to pay for gas. For EVM-based blockchains, the gas is precalculated before the transaction and the gas is consumed while executing the bytecode of the smart contract. However, the gas estimation can be temporarily or consistently inaccurate due to the indeterminacy of the Solidity programming language and network traffic. As developers, we need to pay attention to the code that could cause this gas variation and try to optimize the code.

For example, a gaming smart contract may implement a function to reward winners, like so:

function rewardPlayers() external {
  if (isWinner(msg.sender)) {
    safeTransfer(token, msg.sender, winAmount);
    emit Win(msg.sender, winAmount);
  }
}

If isWinner(msg.sender) determines the winner with some randomness at the time of calling it, it would cause differences between the gas estimation and gas actual usage. This means that the gas estimation assumes that the safeTransfer function is not called, so it assigns a small amount of gas to run the transaction. However, at the time of execution, the caller of the function is selected as the winner, and the safeTransfer call in the if statement exceeds the gas limit, which causes a denial-of-service (DoS) attack.

Iterations can also cause gas overflow if the size of the iteration grows over time. Figure 1.10 shows the relationship between gas usage and the number of iterations:

Figure 1.10 – The relationship between gas usage and the number of iterations (benchmarked with Solidity v0.8.3)

Figure 1.10 – The relationship between gas usage and the number of iterations (benchmarked with Solidity v0.8.3)

Based on the data shown in Figure 1.10, gas usage grows exponentially along with the number of iterations. We need to be careful about arrays of a dynamic size and try to reduce this size when possible.

There are many ways to prevent gas overflow. The key thing is optimizing the Solidity code by following good practices. You can refer to https://dev.to/jamiescript/gas-saving-techniques-in-solidity-324c for some techniques for optimizing your Solidity code to save gas usage.

Random number manipulation

Randomness drives people to play against uncertainties. Nowadays, DeFi projects are increasingly introducing lotteries or other forms of randomness to give bonus rewards to their users and attract more users to use their DeFi applications. However, there is no ideal way to generate random numbers within EVM-compatible blockchains. This may cause attackers to manipulate the random number generation and get the number to steal the assets from the reward pool.

If you want to implement a random number generator with the facilities in EVM, you can use code similar to the following:

/*
 * Returns a random number.
 * If the caller of the function gets a random number
 * that can be divided by 10000, then the caller will win.
 */
function getRandomNumber() private view returns (uint256) {
  return uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender)));
}

As you can see, the getRandomNumber function returns a random integer. Inside the function, it concatenates block.timestamp and msg.sender to generate a long byte array, then hashes the bytes with the keccak256 algorithm to generate a pseudo-random number. Here, msg.sender is the caller’s address, and block.timestamp is the timestamp field of a block in its header. Because the timestamp is set by the miner, a hacker can set the block.timestamp function of the next block by being a miner to generate a random number that makes them win.

To get a true random number, we can use an oracle service such as Chainlink VRF. It relies on many nodes being on the network to generate a random number that is secure and almost impossible to manipulate by hackers. However, this random number retrieval requires a request and a callback to fulfill the request. The duration between the request and its fulfillment may take dozens of seconds to more than one minute, and each request may take an amount of LINK tokens plus the gas fee. As a result, it is better for a smart contract that relies on random numbers such as lottery games to wait for a certain period to reveal rewards instead of doing that on the spot (for example, reveal a group of winners daily or weekly).

To learn how to get random numbers with Chainlink oracle, go to https://docs.chain.link/vrf/v2/subscription/examples/get-a-random-number/.

There are many more types of vulnerabilities in DeFi. We will discuss this in more detail when we build DeFi applications later in this book. Now, let’s summarize what we have learned so far.

bookmark search playlist download font-size

Change the font size

margin-width

Change margin width

day-mode

Change background colour

Close icon Search
Country selected

Close icon Your notes and bookmarks

Delete Bookmark

Modal Close icon
Are you sure you want to delete it?
Cancel
Yes, Delete

Confirmation

Modal Close icon
claim successful

Buy this book with your credits?

Modal Close icon
Are you sure you want to buy this book with one of your credits?
Close
YES, BUY