Back to Blog

Revest Finance Vulnerabilities: More than Re-entrancy

Code Auditing
March 31, 2022

On March 27th, 2022, the staking DeFi project Revest Finance on Ethereum was attacked due to the ERC-1155 call-back mechanism, which caused roughly $2M worth of tokens (namely BLOCKS, ECO, LYXe, and RENA) to be stolen. We analyzed the attack in the first place, and tweeted our analysis on that night (UTC+8).

In fact, at the time of writing the Twitter, we still had some doubts about a function in the Revest TokenVault contract. We looked into the contract trying to understand its functionality. Later we found that it's another critical zero-day vulnerability, which can be exploited in a far more simple way and can cause the same huge losses (as the attack that has happened).

We then contacted the Revest Finance team immediately, and they responded quickly and proposed a workaround for the vulnerability. After confirming the vulnerability cannot be triggered, we decided to release this blog.

The following of this blog consists of three parts: the mechanism of the Revest Finance, the original re-entrancy attack, and the new zero-day vulnerability.

What's the Revest Finance FNFT

The Financial Non-Fungible Token (FNFT) of Revest Finance makes the trustless transfer of future rights to locked assets possible. The entry contract (Revest contract) provides three different interfaces to mint FNFT by locking underlying assets:

  • mintTimeLock: the underlying asset will be unlocked after a period of time.
  • mintValueLock: the underlying asset will be unlocked when its value rises above or falls below a prescribed value.
  • mintAddressLock: the underlying asset will be unlocked by a prescribed account.

The Revest contract connects the other three contracts to lock and unlock underlying assets.

  • FNFTHandler: inherited from the ERC-1155 token. It creates a new FNFT with the incrementing fnftId for every lock. The lock prescribes the total supply of the new FNFT at the creation. The FNFT can not be minted in any other way but can be burned for unlocking underlying assets.

  • LockManager: records the unlocking conditions for each lock when creating and decides if the lock can be unlocked when unlocking.

  • TokenVault: receives and sends the underlying assets and records the metadata for each FNFT, such as the value of a specified FNFT.

We take mintAddressLock as an example to illustrate the process of minting FNFTs.

Figure 1
Figure 2

The above two figures describe how a FNFT is created, minted, and burned. Specifically, user A locks 100 WETH into Revest Finance, creating the corresponding FNFT with fnftId as 1. Finally, it mints 100 1-FNFT to specified recipients with specified shares.

Note that, once the underlying asset is unlocked, then every 1-FNFT can be burned for receiving one (*1e18) WETH. As shown in Figure 2, user B withdraws 25 (* 1e18) WETH by burning 25 1-FNFT.

In addition, the Revest contract provides another interface, named depositAdditionalToFNFT, that incurs two vulnerabilities that will be discussed in the following.

We first use the following two figures to describe the normal usage of this function.

Figure 3
Figure 4

The function depositAdditionalToFNFT locks more underlying assets to an existing lock (specified by fnftId). Reasonably(Figure 3), it requires the specified quantity to be the same as the total supply of specified FNFT and then evenly distributes the added assets to each specified FNFT.

Otherwise(Figure 4), it creates a new lock with the latest fnftId, burns the specified quantities of old FNFT and mints the specified quantity of new FNFT, and then records the new lock's depositAmount as the sum of the old lock's depositAmount and the specified amount, as shown in the following code.

// Now, we transfer to the token vault
if(fnft.asset != address(0)){
    IERC20(fnft.asset).safeTransferFrom(_msgSender(), vault, quantity * amount);
}

ITokenVault(vault).handleMultipleDeposits(fnftId, newFNFTId, fnft.depositAmount + amount);

emit FNFTAddionalDeposited(_msgSender(), newFNFTId, quantity, amount);
```since `depositAmount` recorded in the *TokenVault* contract indicates the amount of the underlying asset one specified FNFT can withdraw, that operation transfers the value of the specified quantities of old FNFT from the old lock to the new lock. 

(Specified quantity greater than the total supply will revert the transaction)

## What's the Re-entrancy Vulnerability

In this part, we will illustrate how the re-entrancy attack works and discuss the root cause and the fix method.

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/re_entrancy_attack1_cddca5d48d.png) 

<center>
Figure 5
</center>

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/re_entrancy_attack2_36cb3f84cd.png) 

<center>
Figure 6
</center>

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/re_entrancy_attack3_2820675f4e.png) 

<center>
Figure 7
</center>

The above three figures basically describe the whole process of the re-entrancy attack.  Specifically, the attacker first locks zero RENA token to mint 2 1-FNFT that has no value. Second, the attacker locks zero RENA token again but mints 360,000 2-FNFT that also has no value (now). During the last step, the attacker re-enters the *Revest* contract's *depositAdditionalToFNFT* function via the *FNFTHandler*'s call-back mechanism inherited from the ERC-1155 token standard, which over-writes the `depositAmount` of the lock with `fnftId` as 2 before updating of `fnftId`. As a result, the attacker obtains 360,001 2-FNFT with the `depositAmount` as 1e18, which means he can withdraw 360,001 * 1e18 RENA from the *TokenVault* contract. Besides, the only cost is 1e18 RENA. 

**Fix Method**

The codes of Revest Finance are completely in line with the classic re-entrancy pattern: use `fnftId` -> external call with callback mechanism -> update `fnftId`. Therefore, the most straightforward way to fix the issues is to break the pattern. The fixed code is shown below:

```javascript
function mint(
    address account, 
    uint id, 
    uint amount, 
    bytes memory data
) external override onlyRevestController {
    require(amount > 0, "Invalid amount");
    require(supply[id] == 0, "Repeated mint for the same FNFT");
    supply[id] += amount;
    fnftsCreated += 1;
    _mint(account, id, amount, data);
}
```first it moves the update operation before the external call (`_mint`), which can avoid the attack. Second, since the system does not allow mint zero FNFT and repeated mint the same FNFT, it adds two checks to ensure the system works as expected, which can improve the system's safety.

## The New Zero-day Vulnerability

When analyzing the code of Revest Finance, the function `handleMultipleDeposits` in the *TokenVault* contract always confuses us, the code of which is shown below.

```javascript
function handleMultipleDeposits(
    uint fnftId,
    uint newFNFTId,
    uint amount
) external override onlyRevestController {
    require(amount >= fnfts[fnftId].depositAmount, 'E003');
    IRevest.FNFTConfig storage config = fnfts[fnftId];
    config.depositAmount = amount;
    mapFNFTToToken(fnftId, config);
    if(newFNFTId != 0) {
        mapFNFTToToken(newFNFTId, config);
    }
}
```during the call to the `depositAdditionalToFNFT` function, the `handleMultipleDeposits` function changes `depositAmount` of the old lock or records it of the new one. When the `newFNFTId` is zero, it does not record the `depositAmount` of the new lock, because this is an operation to add additional assets to the existing lock.

According to common sense, when the `newFNFTId` is not zero, it only records `depositAmount` of the new lock but does not change `depositAmount` of the old one. However, the code tell us that it not only records `depositAmount` of the new lock but changes `depositAmount` of the old one.

We believe that is a serious **zero-day** logic vulnerability and then write a PoC to verify that. The following three figures describe how the PoC works.

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/sim_attack1_dc9df071f5.png) 

<center>
Figure 8
</center>

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/sim_attack2_140e9c0109.png) 

<center>
Figure 9
</center>

 ![](https://blocksec-static-resources.s3.us-east-1.amazonaws.com/assets/frontend/blocksec-strapi-online/sim_attack3_b35639f49a.png) 

<center>
Figure 10
</center>

Specifically, the attacker first locks zero RENA to mint 360,000 1-FNFT. After that, the attacker directly invokes the `depositAdditionalToFNFT` function to create a new lock. Due to the logic bug, the `TokenVault` contract incorrectly changes the `depositAmount` of the old lock from zero to 1e18.  As a result, the attacker gains 359,999 1-FNFT worth of 359,999 RENA.  Obviously, the PoC is far more simple than the real re-entrancy attack. 

## The Workaround to Fix the Vulnerability

This is a logic bug, and we recommend using the following code to fix it.

```javascript
function handleMultipleDeposits(
    uint fnftId,
    uint newFNFTId,
    uint amount
) external override onlyRevestController {
    require(amount >= fnfts[fnftId].depositAmount, 'E003');
    IRevest.FNFTConfig memory config = fnfts[fnftId];
    config.depositAmount = amount;
    if(newFNFTId != 0) {
        mapFNFTToToken(newFNFTId, config);
    } else {
        mapFNFTToToken(fnftId, config);
    }
}
```since the two vulnerable contracts: *TokenVault* and *FNFTHandler* store a lot of critical states, the project can not re-deploy the *TokenVault* contract and the *FNFTHandler* contract without migrating states. To avoid the further attack to this vulnerability, the project re-deployed a lite version of  [*Revest* contract](https://etherscan.io/address/0x36c2732f1b2ed69cf17133ab01f2876b614a2f27#code), which disables more complex functions to reduce the surfaces available to any would-be attacker. After checking the workaround, we believe that the lite *Revest* contract can mitigate the possible attacks mentioned in this blog. 

## Takeaway

Making a DeFi project secure is not an easy job. Besides the code audit, we think the community should take a proactive method to monitor the project status, and [block the attack before it even takes place](https://blocksec.com/phalcon).

## About BlockSec

BlockSec is a pioneering blockchain security company established in 2021 by a group of globally distinguished security experts. The company is committed to enhancing security and usability for the emerging Web3 world in order to facilitate its mass adoption. To this end, BlockSec provides smart contract and EVM chain security auditing services, the Phalcon platform for security development and blocking threats proactively, the MetaSleuth platform for fund tracking and investigation, and MetaDock extension for web3 builders surfing efficiently in the crypto world.

To date, the company has served over 300 esteemed clients such as MetaMask, Uniswap Foundation, Compound, Forta, and PancakeSwap, and received tens of millions of US dollars in two rounds of financing from preeminent investors, including Matrix Partners, Vitalbridge Capital, and Fenbushi Capital.

Official website: [https://blocksec.com/](https://blocksec.com/)

Official Twitter account: [https://twitter.com/BlockSecTeam](https://twitter.com/BlockSecTeam)
Sign up for the latest updates
Tracing $1.6B in TRON USDT: Inside the VerilyHK Ponzi Infrastructure
Case Studies

Tracing $1.6B in TRON USDT: Inside the VerilyHK Ponzi Infrastructure

An on-chain investigation into VerilyHK, a fraudulent platform that moved $1.6B in TRON USDT through a multi-layered fund-routing infrastructure of rotating wallets, paired payout channels, and exchange exit funnels, with traced connections to the FinCEN-sanctioned Huione Group.

Weekly Web3 Security Incident Roundup | Mar 30 – Apr 5, 2026
Security Insights

Weekly Web3 Security Incident Roundup | Mar 30 – Apr 5, 2026

This BlockSec weekly security report covers nine DeFi attack incidents detected between March 30 and April 5, 2026, across Solana, BNB Chain, Arbitrum, and Polygon, with total estimated losses of approximately $287M. The week was dominated by the $285.3M Drift Protocol exploit on Solana, where attackers combined multisig signer social engineering with Solana's durable nonce mechanism to bypass a zero-timelock 2-of-5 Security Council, alongside notable incidents including a $950K flash loan TWAP manipulation against the LML staking protocol, a $359K Silo Finance vault inflation via an external `wstUSR` market donation exploiting a depegged-asset oracle and `totalAssets()` accounting flaw, and an EIP-7702 delegated-code access control failure. The report provides detailed vulnerability analysis and attack transaction breakdowns for each incident, covering flawed business logic, access control, price manipulation, phishing, and misconfiguration attack types.

Drift Protocol Incident: Multisig Governance Compromise via Durable Nonce Exploitation
Security Insights

Drift Protocol Incident: Multisig Governance Compromise via Durable Nonce Exploitation

On April 1, 2026 (UTC), Drift Protocol on Solana suffered a $285.3M loss after an attacker exploited Solana's durable nonce mechanism to delay the execution of phished multisig approvals, ultimately transferring administrative control of the protocol's 2-of-5 Squads governance with zero timelock. With full admin privileges, the attacker created a malicious collateral market (CVT), inflated its oracle price, relaxed withdrawal protections, and drained USDC, JLP, SOL, cbBTC, and other assets through 31 rapid withdrawals in approximately 12 minutes. This incident highlights how durable nonce-based delayed execution can decouple signer intent from on-chain execution, bypassing the temporal assumptions that multisig security implicitly relies on.

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit