Tokenomics is the study and design of economic systems and models based on blockchain tokens, encompassing aspects like distribution, utility, and the incentives that drive the behavior of token holders within a particular blockchain ecosystem. Staking in Decentralized Finance (DeFi) allows users to earn passive income by locking their tokens. This benefits both users and platforms. Tokenomics is a crucial consideration in staking protocols, as it determines rewards for locked assets. However, any flaws in the design can be exploited, as seen in three case studies that we’ll examine in this piece.
Security recommendations include adding time factors and delay mechanisms to ensure fair reward distribution and protect DeFi projects from such exploits.
Staking enables token holders to earn passive interest and rewards by locking their tokens in staking contracts. This article focuses solely on staking in the context of Decentralized Finance (DeFi), rather than Proof-of-Stake as a consensus algorithm in blockchain.
Staking presents a win-win scenario for both users and the platform.
For users:
For the Platform:
Tokenomics is the study of the economic impact of a token, taking both macro and micro perspectives into account.
On the macro level, tokenomics examines token issuance, airdrop strategies, allocation methods, token circulation, and the application of deflationary or inflationary measures to control token price and demand. The associated analysis is commonly referred to as a tokenomics audit.
On the micro level, tokenomics overlaps with part of Cryptoeconomics, a field pioneered by Vlad Zamfir and Vitalik Buterin, which focuses on the incentive mechanism design of the consensus protocol, including all kinds of incentive calculation and distribution, and governance model design. Understanding these elements is vital, as any loopholes can be exploited by malicious individuals.
Tokenomics of staking refers to the mathematical design that calculates the staking reward for the locked asset. In practical scenarios, available staked tokens cannot be unlimited. Constraints such as the total staked supply and other users' participation become critical factors in determining individual rewards. Thus, the portion between an individual’s staked amount and the total available staked tokens or all the participants' staked value often serves as the metric to evaluate one's staked value. To realize the lock effect, the time factor is also critical in the reward calculation. Intuitively, the staking reward calculation might follow a formula reflecting these principles. For example, it could look something like the following:
Where sj
represents the amount an individual has staked, while Sj
denotes the total tokens available for staking in the system. Generally, the reward rate R
is a predefined constant or variable. The summation symbol indicates the cumulative duration of the staking value, starting from time k
and extending up to the exit time t
.
A well-constructed tokenomic design in staking projects typically encompasses these critical variables, ensuring they are well-managed and updated throughout the entire system. Neglecting or mishandling one or more aforementioned variables can expose the system to severe risks, resulting in significant losses for the DeFi ecosystem. In the following sections, we delve into several real-world case studies of typical tokenomics exploits. We will break down the attack flow and highlight the vulnerabilities in the tokenomic designs.
On November 21, 2022, CertiK's Skynet detected an exploit within the staking contract sDAO of the SportsDao project. This exploit arises because anyone can reduce the total staked balance, Sj
, using a public withdrawTeam()
function without any time factor t considered in the tokenomic design. The total profit from this exploit was calculated to be approximately 13.7K BSC-USD.
The illustration below details the SportsDao exploit. The sequence starts with the attacker flash loaning 500 USDT and swapping 250 USDT for 5,676 sDAO. Then, the attacker used 2,838 sDAO and 114 USDT to add liquidity and received 483 LP from the USDT-sDAO pool. After staking 241 LP in the sDAO contract, the attacker triggers a transfer of all LP tokens from the sDAO contract to the TEAM wallet by exploiting the public function withdrawTeam()
. With the reduced LP in the sDAO contract, the attacker manipulates the reward calculation to their advantage, leading to the conversion of the inflated sDAO rewards into 14K BSC-USD. Subsequently, these funds are moved to the attacker's account and used to pay back the flash loan.
Examine the attack transaction here.
The root cause stems from a design flaw in the tokenomics, specifically within the token reward mechanism. In this setup, rewards are computed only on the proportion of a user's staked amount relative to the total staked amount. The tokenomics design does not account for the time factor and the project lacks a delay mechanism. As a result, users can stake and immediately claim rewards in the same block. This creates a vulnerability, allowing attackers to boost their staked amount quickly and unfairly claim larger rewards using flashloan. The following code snippet illustrates the flawed reward calculation within the tokenomic design:
The code snippet above shows the pendingToken()
and getPerTokenReward()
functions, which contain the core logic for calculating rewards. The calculation can be simplified and presented as follows:
This reward calculation has two vulnerabilities:
Each of the vulnerabilities mentioned above presents a distinct attack vector, and both can be independently exploited by attackers. In the SportsDao exploit, the attacker utilized both:
withdrawTeam()
function to decrease the total LP amount, thereby successfully inflating its own reward.Integrate a time factor into the tokenomics design to ensure fair reward distribution.
Implement a delay mechanism to prevent simultaneous stake, unstake, and reward claim operations within a single block.
On November 17, 2022, the Skynet system identified a flashloan exploit on UEarnPool. The root cause is that individuals can inflate their staked ratio, sj/Sj, using the public bindInvitor() function without considering the time factor t in the tokenomics design. The total profit of this exploit is 16,038 USDT.
Before the attack unfolded, several helper contracts were set up and subsequently invoked the bindInvitor()
function of UEarnPool to become the invitors. The exploit was initiated with a flash loan of 2.4M USDT and involved a series of repeated stake operations.
In each of these operations, the UEarnPool would allocate a fraction of the staked amount to the invitors of the function caller. Starting from the second staking action, one of the invitors would initiate the subsequent staking round. This would prompt the UEarnPool to distribute rewards to the invitors once more while also allocating the claimable reward back to the function caller.
After each attack cycle, the accumulated rewards were channeled from the helper contracts to the attacker, ensuring the flash loan was repaid. The attacker has drained the UEarnPool funds by employing the flash loan and setting up 20 helper contracts as invitors, successfully inflating the portion eligible for reward redemption. The illustration provided below offers a concise overview, focusing solely on the first two rounds of the staking operations.
Examine the attack transaction here.
In examining the staking contract's codebase, the first vulnerability resides in the claimTeamReward()
function, specifically within the level reward calculation code snippet.
The level reward calculation is presented as follows:
Within a specific, predefined levelConfig
, all attributes, including rewardRate
, teamAmount
, and amount
, are set and remain constant. The tokenomic design lacked a time factor, and the staking contract did not incorporate any delay mechanism, implying that any user with valid level information can stake tokens and claim a consistent reward within the same block.
Delving into the getUserLevel()
function, it's evident that the level information can be updated via the stake operation. With the stake()
function, two internal functions are invoked: _addInviteReward()
and _addTeamAmount()
. These functions respectively update the invite reward and level data.
The second vulnerability can be pinpointed within the _addInviteReward()
function:
The invite reward calculation is presented as follows:
Just as with the level reward design, the invite reward fails to include any time-related variable in its formula. This function directly allocates invite rewards to invitor based solely on the staked amount. If a single entity controls all the invitor accounts, they can retrieve a portion of the staked tokens without any constraints, making the actual staked amount less than the specified amount.
In conclusion, the flawed level reward design allows attackers to use flash loans to inflate their staked portion. Coupled with the defective invite reward design, where attackers can claim rewards based on the amount even when the real staked sum is lower, it provides malevolent actors with avenues to accrue undue advantages.
Integrate a time factor into the tokenomic design to ensure fair reward distribution.
Implement a delay mechanism to prevent simultaneous stake, unstake, and reward claim operations within a single block.
On August 13, 2022, at 08:37:47 AM UTC, the warpStaking system experienced an exploit, resulting in a loss of 0.09BTCB, equivalent to $2,294. The root cause for this exploit was price manipulation within the BTCB-WRP liquidity pool, upon which the staking reward rate depends.
The reward calculation is designed to calculate rewards based on a rate determined by the ratio of BTCB reserves to WRP reserves in the BTCB-WRP pool. However, this pool lacks depth, making it vulnerable to manipulation through standard swapping operations. The attacker exploited this by swapping a specific amount of BTCB for WRP. This action increased the BTCB reserve while decreasing the WRP reserve in the pool, thereby amplifying the ratio between the two values.
Before the attack, the attacker swapped 0.3016 BNB for 2,500 WRP and sent them to the helper contract at 0xf7bc. This contract staked the WRP in WarpStaking and received 2,500 warpWRP(120D) tokens.
The illustration below provides a detailed breakdown of the WarpStaking exploit. The major exploit logic, executed within the helper contract (referred to “Attacker“ in the illustration), began with a flash loan of 2 BTCB from the WBNB-BTCB pool. The attacker then swapped 1.5 BTCB for 4,336 WRP, increasing the reserve ratio. After sending 0.002 BTC to the WarpStaking contract and invoking the harvest()
function, the attacker received a reward of 0.102 BTCB. The attacker swapped back 4,336 WRP for 1.499 BTCB, repaid 2.006 BTCB to the flash loan pool, and finally secured a profit of 0.093 BTCB.
Examine the attack transaction here.
The vulnerability stems from the tokenomics design, where the reward rate is derived from the real-time reserve values of the WRP-BTCB pool. These reserve values are susceptible to manipulation through swap operations.
According to the tokenomics-related functions from WarpStaking.sol , the reward calculation is presented as follows:
Given the context where lpReserve0
represents the reserve value of BTCB and lpReserve1
signifies the reserve value of WRP, let's examine the changes in the reward rate rewardTokenPriceInToken
:
Before the swap:
reserve0
is 7,137,630,656,486,809.reserve1
is 4,357,124,478,750,809,250,391.After the swap:
reserve0
rises to 1,507,137,630,656,486,809.reserve1
drops to 20,686,311,779,803,983,947.As a result, the reward rate has been manipulated by the swap operation, effectively amplifying the rewards claimed.
Avoid using the ratio of real-time reserve values to present the reward token price.
In this article, we've examined the fundamental tokenomics of DeFi staking projects. By analyzing three specific exploits, we've illustrated the typical design flaws in tokenomics. These case studies underscore the importance of accurately managing essential components such as the individual staked balance, the total staked balance, the reward rate, and the time factor. Proper attention to these elements is imperative to ensure the stability and security of decentralized financial platforms.
As the case studies have demonstrated, the tokenomics design flaws are typically intricate and elusive, posing significant challenges for general security audits. When malicious entities exploit these flaws, the resulting losses can be staggering. The crux of the matter is that when several vulnerabilities persist within a tokenomic structure, their combined risks can intensify, exponentially increasing the chances of unauthorized benefits.
To ensure the integrity and security of DeFi projects, it is imperative that we prioritize smart contract audits with a keen focus on tokenomic design. These audits extend beyond code review and into the intricate economic incentives underlying these systems. By embracing thorough tokenomic audits, we fortify our defenses against vulnerabilities, fostering a safer and more sustainable DeFi landscape that benefits all stakeholders.