Sentiment, an undercollateralized lending protocol, appears to have been exploited on April 4 for over $500,000 in crypto. Ethereum blockchain data shows a transaction that transferred 536,738.410031 USD Coin (USDC) from the Synapse Bridge, and this links up with a series of Arbitrum transactions draining coins from Sentiment. 

The wallet performing the attack has been labeled “Sentimentxyz Exploiter” by Arbiscan, and the Sentiment team has announced on Twitter that they are aware of a “potential issue” with the protocol.

Twitter user Officer’s Notes has suggested that this may be a reentrancy attack. The user relied on research done by Twitter user FrankResearcher to come to this conclusion.

The Sentiment team has not yet stated what steps are being performed to stop the attack or what users should do to mitigate risk.

Further investigation reveals that the attacker created a Sentiment BeaconProxy contract and used it to change balances in a pool at Balancer and to make a series of borrows and transfers into the contract. Some of the tokens sent into this BeaconProxy contract were then transferred into the attacker’s account.

Analysis from Gearbox Protocol developer Mikhail Lazarev suggests that the attacker may have relied on a bug caused by interactions between Balancer and Sentiment to withdraw assets before prices on Sentiment were updated.

At least three smart contracts were used to perform the attack, one of which failed and had to be replaced. The code for two of the contracts was wiped through self-destructs after the attack was completed.

The attacker began by deploying a contract to the Arbitrum network at the following address:

0xa4d063b9468b93aee2a87ec7072c3dabd5ee5968.

They then called the “run” function on this contract a minute later. However, this function-call failed, producing a “Fail with error 'BAL#420” response. The attacker responded by calling the “self-destruct” function on the contract, which succeeded. This erased all of the contract’s code from the blockchain.

After destroying this contract, the attacker redeployed at the following address: 0x9f626F5941FAfe0A5b839907d77fbBD5d0deA9D0.

They then called the “run” function once again. This time, it succeeded, causing the contract to perform a series of transactions. One of these transactions created a Sentiment account or “BeaconProxy” contract at 0xdf346f8d160424c79cb8e8b49b13dd0ca61c3b8c.

This BeaconProxy contract was used to change the pool balance in a Balancer pool, emitting a PoolBalancesChanged event.

Balancer pool being changed during Sentiment attack. Source: Arbitrum blockchain data

The BeaconProxy also made a series of borrows and transfers that drained tokens from the Sentiment protocol. Some of the tokens were transferred afterwards into the attacker’s individual account, while others were used to pay back a flash loan from Aave.

Arbitrum blockchain data does not make clear whether the transfers happened first or the pool change did, as transactions are not always listed in logs according to their logical order.

However, in his analysis, Lazarev stated that these transfers were made before the PoolBalancesChanged event was emitted, but after the pools had actually been changed. This was allowed to happen because Balancer doesn’t update its balances until after assets are sent to the user.

Lines 258-280 of the Balancer PoolBalances.sol contract shows that balances are updated on line 278, whereas tokens are sent to the recipient beginning on line 271.

In Lazarev’s view, this allowed the attacker to “[manipulate] these values to overprice his collateral and then borrow and withdraw sentiment pool assets.”

Once the attack was finished, the attacker destroyed the contract that had created the BeaconProxy, blockchain data shows.

Sentiment attacker contract after being self-destructed. Source: Arbitrum blockchain data

This story was updated on April 5, 2023 to include analysis from Gearbox Protocol developer Mikhail Lazarev and to correct an error that had stated that the hack may have been due to a stolen deployer key.