The Bonq Dao attack

Think and Dev
Think and Dev
Published in
5 min readFeb 3, 2023

Bonq Dao is a Lending protocol (similar to Venus or Compound) where you can stake your tokens and use them as collateral to mint BEUR, a stablecoin soft pegged to Euro. It uses Tellor.io decentralized oracle protocol to obtain the token prices so it can calculate the loan-to-value ratio (LTV). If you don’t know what a collateralized loan is see this article.

The attack happened on the polygon blockchain on Feb-01–2023 06:29:18 PM +UTC. The attacker manipulated the oracle price and exploited the Bonq Dao protocol to obtain 98 million BEUR and 113.8 million ALBT tokens.

Think and Dev is a dev shop specializing in web3 development including solidity smart contracts. As Alliance Block is one of our customers, we performed an investigation to see if the ALBT protocol was breached.

The attack

The attack consisted of 2 transactions, the first one setting an incredibly high price for ALBT token, then he deposited 0,1 ALBT as collateral and was able to borrow 100 million BEUR.

This was possible because Tellor Oracle allows anyone to participate as long as they stake enough TRB, at the moment that is 10 TRB which is equivalent to 168.60 u$d. At Think and Dev, we think that the value is too low, and slashing such a small value does not represent a big penalty for bad behavior. But that’s not the real issue, the real issue is that Bonq is using the latest price from Tellor Oracle Protocol when they should use a buffer of at least 20 minutes as described in their documentation so the value can be disputed.

For the second transaction, he set the ALBT price to almost 0, causing all the loans made using ALBT to be undercollateralized. Then he used the previously obtained BEUR to liquidate those undercollateralized loans obtaining 113.8 million ALBT.

The reason why he targeted ALBT is that it had the biggest liquidity in the Bonq protocol and is tradable in several markets. The attacker managed to sell the assets for $1M worth in ETH and $500K in DAI so far and seems to be stuck. Currently, more than 98MIL BEUR are still on the attacker’s account on Polygon with no liquidity to exit. Alliance Block paused all of its protocols and is creating a new token airdrop, so the attacker can’t use the stolen ALBT and users will obtain the new one.

Step-by-step details

The attacker 0xcacf2d28b2a5309e099f0c6e8c60ec3ddf656642 created a Smart contract 0xed596991ac5f1aa1858da66c67f7cfa76e54b5f1 so he can modify the price and interact with the protocols on a single transaction.

The first transaction

https://polygonscan.com/tx/0x31957ecc43774d19f54d9968e95c69c882468b46860f921668f2c55fadd51b19

The attacker transferred 10 TRB to the 0xbaf48429b4d30bdfad488508d3b528033331fe8a smart contract and adds it as a new member in Toller Oracle protocol using the 10 TRB for staking (see the logs)

Then calls the submitValue function from TellorFlex.sol adding a new report to the Toller Oracle where the ALBT value is way high 0x1027E72F1F12813088000000 (u$d 5000000000) (see the logs)

Then it stakes 0.1 ALBT into Benq Trove contract 0x4248fd3e2c055a02117eb13de4276170003ca295

As the price was manipulated the Trove allows borrowing over 100 Million BEUR for the staked 0.1 ALBT

How Trove contract calculates the price? It uses:

/**
* @dev the value of the collateral * the current price as returned by the price feed contract for the collateral token
*/
function collateralValue() public view override returns (uint256) {
return (normalisedDecimals(collateral()) * factory.tokenToPriceFeed().tokenPrice(address(token))) / DECIMAL_PRECISION;
}

If we get the information from the contracts we will obtain:
Factory address is 0x3bb7ffd08f46620bea3a9ae7f096cf2b213768b3
TokenPriceFeed is 0x20d50159aff262f953c8913ec859cac13a010b8a
And tokenPrice function is

/// @dev to get token price
/// @param _token address of the token
function tokenPrice(address _token) public view override returns (uint256) {
return IPriceFeed(tokens[_token].priceFeed).price();
}

If we check the value for the mapping using ALBT token

Price Feed is 0x7D4c36c79b89E1f3eA63A38C1DdB16EF8c394bc8 and corresponds to ConvertedPriceFeed smart contract. If we call priceFeed method

That points to TellorPriceFeed smart contract (finally!) 0xa1620af6138d2754f7250299dc9024563bd1a5d6

The Mistake

If we look at tellor-price-feed.sol the function price looks like

function price() public view virtual override returns (uint256) {
return uint256(bytes32(oracle.getCurrentValue(queryId)));
}

The oracle from the previous function is TellorFlex.sol 0x8f55d884cad66b79e1a131f6bcb0e66f4fd84d5b

/**
* @dev Returns the current value of a data feed given a specific ID
* @param _queryId is the ID of the specific data feed
* @return _value the latest submitted value for the given queryId
*/
function getCurrentValue(bytes32 _queryId)
external
view
returns (bytes memory _value)
{
bool _didGet;
(_didGet, _value, ) = getDataBefore(_queryId, block.timestamp + 1);
if(!_didGet){revert();}
}

And here it’s not waiting for any time for disputes as advised by Tellor’s Docs and the example provided. It should be

   (_didGet, _value, ) = getDataBefore(_queryId, block.timestamp - 20 minutes);

Not using the time buffer is what allowed the attacker to manipulate the price and perform the exploit.

Second Transaction

In a follow-up tx https://polygonscan.com/tx/0xa02d0c3d16d6ee0e0b6a42c3cc91997c2b40c87d777136dedebe8ee0f47f32b1

This time reporting to the Oracle that $ALBT price was 0x174876E800 (u$d 0,0000001).

As the value now dropped, all (33) ALBT troves are under-collateralized allowing them to be liquidated. And that’s what the attacker did, using 1.3M BEUR previously obtained, to pay for the liquidated $ALBT tokens, getting away with 113.8 Million $ALBT

The actor then walks away by withdrawing the illicit gains with 113.8M WALBT and 98M BEUR (valued >$5M). Some of these tokens are then dumped, resulting in a major drop! ALBT dropped by >50% and BEUR dropped by 34%. The attacker managed to get $1M worth in ETH and $500K in DAI so far and seems to be stuck now.

Conclusion

Alliance Block and Tellor Oracles were not breached, only Bonq was. Blockchain programming is hard, there is no room for error in the smart contracts. The code is public and accessible to anyone and can’t be rolled back to a previous state.

This is why at Think and Dev dev shop we only offer senior blockchain developers for creating smart contracts, if you need this kind of service please write us at hello@thinkanddev.com

--

--