Interested in learning about liquidations and rewards? Continue reading Part II of this series! 🙂
13/02/2024
In this long article, you will learn the core concepts of what make DeFi tick, how it differs from traditional finance and the main use-cases and commercial applications DeFi has found in our world today.
1. Lending and borrowing
2. Liquidations
As opposed to centralized liquidity locations in traditional finance, DeFi crowd-funds the liquidity pools from regular and professional users, giving the user a much bigger leeway when it comes to paying back the borrowed amount, upon overcollateralization.
The predominantly collateralized loan structure offered by most DeFi lending protocols uncovers an intriguing strategy for trading:Â leveraging.
Assume, for instance, that you have a strong positive outlook on the price of Ethereum (ETH) — absolutely confident that it’s on an upward trajectory. You might deposit a certain amount of ETH (let’s say, worth $1000) into a DeFi lending protocol of your choice. Then, you could leverage this deposit to borrow a stablecoin, like DAI, and subsequently use that to acquire more ETH. For this illustration, consider that you buy an additional $500 worth of ETH on an exchange, exposing your ETH exposure to $1500 from your initial $1000 investment.
However, the strategy can be expanded further. What if you used the additional $500 worth of ETH you just bought as collateral to borrow more DAI? This method, referred to as over-leveraging, can be repeated until the protocol’s policies restrict you, typically when your borrowing limit is exceeded.
On the flip side, suppose your perspective on ETH is less than optimistic. In such a scenario, you could deposit DAI as collateral to borrow ETH, which you would immediately swap for more DAI. If your forecast holds and ETH prices fall, you could repurchase the borrowed amount for less on an exchange, repay your loan, and pocket the remaining DAI. This effectively opens (and subsequently closes) a short position on ETH, thereby capitalizing on its declining market value.
Dangers?
In the world of Decentralized Finance (DeFi), akin to traditional finance (TradFi), depositors are encouraged to keep their assets in lending pools for longer durations through the incentive of accruing interest over time. The interest gained is a calculated percentage of a user’s deposit, as determined by the protocol, and can be claimed by the user who deposited. As the duration of asset retention in the lending pool increases, so does the interest accumulated.
The question that arises is how does the protocol maintain a record of each user’s proportionate share in the pool? It’s crucial to understand that as a user deposits assets into the pool, the shares of all existing users are diluted, and this change is factored in by the protocol. Yet, the protocol does not continually monitor and adjust each user’s share directly with every deposit or withdrawal transaction. Implementing such a system on-chain would not only be enormously inefficient but also excessively costly for depositors, who would bear the expenses for each update operation.
Instead, the protocol is designed to only manage the change in the share of the depositor, without needing to actively adjust the shares of other users.
It might appear at first glance that this protocol system allows users to enjoy all the benefits without any trade-offs, but it’s not entirely so:
Protocols manage the process of interest distribution by creating (minting) and destroying (burning) ERC20 tokens, which we’ll call “Stake Tokens” for this discussion. These Stake Tokens represent the percentage of assets a lender has deposited in the lending pool. This Stake Token mechanism automatically compensates for the dilution of other stakeholders’ shares when Stake Tokens are minted or burned, correlating with the deposit or withdrawal of the underlying assets.
Let’s review an easy example:
Let’s create a simplified visual example of how this system might work using the concept of “Stake Tokens” or “Share Tokens”. We’ll be using hypothetical figures for the sake of easy understanding.
Let’s imagine there’s a lending pool called “Pool A”, and currently, there are only two users who have deposited assets into it, Alice and Bob. Alice has deposited 500 DAI, and Bob has deposited 500 DAI as well. So, the total value of the pool is 1000 DAI.
In return, the protocol has minted 1000 Stake Tokens, with Alice and Bob each holding 500 Stake Tokens, representing their respective shares in the pool.
Now, suppose Charlie comes along and deposits 500 DAI into Pool A. The total pool is now 1500 DAI. However, the protocol doesn’t immediately mint more Stake Tokens. Charlie’s deposit dilutes the shares of Alice and Bob, but their Stake Tokens remain the same.
However, when Charlie wants to withdraw his funds or earn interest, the protocol mints Stake Tokens for Chrlie. Suppose the protocol mints 500 Stake Tokens for Charlie, the total Stake Tokens in the pool will now be 1500.
The Stake Tokens are an efficient way for the protocol to keep track of each depositor’s share in the pool without having to continually adjust everyone’s shares with each deposit or withdrawal. Each Stake Token can be thought of as a claim on the underlying assets in the pool, and their value adjusts automatically as more assets are deposited or withdrawn.
(Please note that this is a simplified example and actual DeFi protocols may operate with more complexity and additional safety measures to protect the lenders and borrowers).
🤿 Now, let’s dive deep into Aave’s Share Token:
First, Aave is a decentralized non-custodial liquidity markets protocol where users can participate as suppliers or borrowers. Suppliers provide liquidity to the market to earn a passive income, while borrowers are able to borrow in an overcollateralized (perpetually) or undercollateralized (one-block liquidity) fashion.
Alright, let’s break this down by first understanding the individual concepts and then tying them together:
1. Decentralized: This term refers to the lack of a central authority or entity controlling a system. Instead, control is distributed among various participants in the system. In the case of blockchain technology, this typically involves a network of computers (known as nodes) that maintain a shared ledger of transactions (the blockchain).
2. Non-custodial: This is a type of financial service where the service provider does not hold or control user assets. Instead, the assets are under the control of the user, typically secured by cryptographic methods. The user usually controls the private key that allows access to the assets.
3. Liquidity markets protocol: This is a fancy term for a set of rules that govern a market where assets can be quickly bought or sold without causing significant changes in their prices. In the context of DeFi, a liquidity market protocol would be the rules and mechanisms that allow users to lend or borrow assets.
4. Suppliers and Borrowers: These are the participants in the market. Suppliers (also known as lenders) provide assets to the market, while borrowers take assets from the market. The terms are borrowed from traditional finance but are used in the same way in the DeFi space.
5. Liquidity: In the context of DeFi, liquidity typically refers to the availability of assets in a market. If a market has a lot of assets (like a cryptocurrency) available to buy or sell, it has high liquidity.
6. Passive income: This is income earned without active involvement. In this context, suppliers earn passive income by providing their assets to the market, which are then borrowed by other users. They earn interest on these assets as a form of passive income.
7. Overcollateralized and Undercollateralized: Collateral is an asset that a borrower offers as a guarantee to a lender. If the borrower fails to pay back the loan, the lender can seize the collateral. Overcollateralized means the value of the collateral is greater than the value of the loan. Undercollateralized means the value of the collateral is less than the value of the loan.
8. One-block liquidity: This term is unique to blockchain-based systems. A “block” refers to a group of transactions that are processed together on a blockchain. In this context, “one-block liquidity” refers to the ability of the Aave protocol to process a loan in a single block of transactions.
Now, let’s have a look at its smart contracts (directly from GitHub), responsible of handling when users deposit liquidity into the protocol. Please note that I have extracted the relevant code snippets, to make it faster for you to read:
The source code can be found here:Â https://github.com/aave/aave-v3-core/tree/master
The borrowing process in Aave is divided into these main parts:
Here is the code snippet for the borrowing function:
function executeBorrow(
mapping(address => DataTypes.ReserveData) storage reservesData,
mapping(uint256 => address) storage reservesList,
mapping(uint8 => DataTypes.EModeCategory) storage eModeCategories,
DataTypes.UserConfigurationMap storage userConfig,
DataTypes.ExecuteBorrowParams memory params
) public {
// ...
if (params.interestRateMode == DataTypes.InterestRateMode.STABLE) {
(
isFirstBorrowing,
reserveCache.nextTotalStableDebt,
reserveCache.nextAvgStableBorrowRate
) = IStableDebtToken(reserveCache.stableDebtTokenAddress).mint(
params.user,
params.onBehalfOf,
params.amount,
currentStableRate
);
} else {
(isFirstBorrowing, reserveCache.nextScaledVariableDebt) = IVariableDebtToken(
reserveCache.variableDebtTokenAddress
).mint(params.user, params.onBehalfOf, params.amount, reserveCache.nextVariableBorrowIndex);
}
// ...
}
The borrowing action is executed in the executeBorrow() function. It checks if the user is eligible for a borrow operation with ValidationLogic.validateBorrow(), updates the state of the reserve with reserve.updateState(reserveCache), and mints the corresponding debt tokens.
executeBorrow()Â function. The type of the debt tokens (stable or variable) depends on the chosen interest rate mode.
function executeRepay(
mapping(address => DataTypes.ReserveData) storage reservesData,
mapping(uint256 => address) storage reservesList,
DataTypes.UserConfigurationMap storage userConfig,
DataTypes.ExecuteRepayParams memory params
) external returns (uint256) {
// ...
if (params.interestRateMode == DataTypes.InterestRateMode.STABLE) {
(reserveCache.nextTotalStableDebt, reserveCache.nextAvgStableBorrowRate) = IStableDebtToken(
reserveCache.stableDebtTokenAddress
).burn(params.onBehalfOf, paybackAmount);
} else {
reserveCache.nextScaledVariableDebt = IVariableDebtToken(
reserveCache.variableDebtTokenAddress
).burn(params.onBehalfOf, paybackAmount, reserveCache.nextVariableBorrowIndex);
}
// ...
}
2. Interest Rate Swap: Borrowers can switch between the stable and variable interest rates at any time.
Here is the code below:
function executeRepay(
mapping(address => DataTypes.ReserveData) storage reservesData,
mapping(uint256 => address) storage reservesList,
DataTypes.UserConfigurationMap storage userConfig,
DataTypes.ExecuteRepayParams memory params
) external returns (uint256) {
// ...
if (params.interestRateMode == DataTypes.InterestRateMode.STABLE) {
(reserveCache.nextTotalStableDebt, reserveCache.nextAvgStableBorrowRate) = IStableDebtToken(
reserveCache.stableDebtTokenAddress
).burn(params.onBehalfOf, paybackAmount);
} else {
reserveCache.nextScaledVariableDebt = IVariableDebtToken(
reserveCache.variableDebtTokenAddress
).burn(params.onBehalfOf, paybackAmount, reserveCache.nextVariableBorrowIndex);
}
// ...
}
The interest rate mode can be swapped in the executeSwapBorrowRateMode() function. It validates the swap with ValidationLogic.validateSwapRateMode(), updates the story ate of the reserve, and burns the current debt tokens and mints new ones in the chosen interest rate mode.
Interested in learning about liquidations and rewards? Continue reading Part II of this series! 🙂
Subscribe now to keep reading and get access to the full archive.