Biconomy Hyphen 2.0 contest - hyh's results

Next-Gen Multichain Relayer Protocol.

General Information

Platform: Code4rena

Start Date: 10/03/2022

Pot Size: $75,000 USDT

Total HM: 25

Participants: 54

Period: 7 days

Judge: pauliax

Total Solo HM: 10

Id: 97

League: ETH

Biconomy

Findings Distribution

Researcher Performance

Rank: 5/54

Findings: 3

Award: $5,540.82

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: WatchPug

Also found by: hyh

Labels

bug
duplicate
3 (High Risk)

Awards

1867.6947 USDT - $1,867.69

External Links

Lines of code

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L244

Vulnerability details

Impact

Remainder nft.unpaidRewards are lost and cannot be retrieved after LiquidityFarming.withdraw. I.e. it is not possible to extractRewards for unpaidRewards later if withdraw being called when balance wasn't sufficient to fulfil the full withdraw of the rewards due, which is reasonably inconvenient to estimate for a user in advance

Proof of Concept

LiquidityFarming._sendRewardsForNft is being called by user facing withdraw and extractRewards functions.

There, when the balance isn't sufficient for full rewards transfer to a user, the remainder is stored in unpaidRewards variable:

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L134-L160

If this happens during extractRewards call, it is possible to run reward gathering again later, when there is enough balance to retrieve unpaidRewards:

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L259

However, when reward token balance happened to be not sufficient during LiquidityFarming.withdraw, the unpaidRewards will be lost for the user as nftInfo structure required for reward gathering logic is unconditionally deleted:

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L244

A way to enable the residual reward retrieval after the withdraw can be introduced to extractRewards -> _sendRewardsForNft logic.

For example, instead of deletion of the nftInfo structure, a flag can be set indicating that stake is no longer active, but remainder rewards are to be retrieved. When extractRewards is being called with this flag on, only nft.unpaidRewards retrieval is attempted

#0 - ankurdubey521

2022-03-30T10:13:49Z

Duplicate of #135

#1 - pauliax

2022-05-02T12:07:22Z

#135

Findings Information

🌟 Selected for report: WatchPug

Also found by: hyh

Labels

bug
duplicate
3 (High Risk)

Awards

3112.8246 USDT - $3,112.82

External Links

Lines of code

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L218

Vulnerability details

Impact

On a combination of high enough token value and low enough decimals there can be not enough precision to store reward amount, which can be permanently hid from a user as a result. I.e. on such a combination there will effectively be no rewards for some users as the reward amount calculations will yield zeros due to not having enough decimals to store the value.

For example, if the amount is 0.01 WBTC, accTokenPerShare is 1e-7 (1e-7 of WBTC is rewarded per 1 staked WBTC; this can be the case at the start, when not much rewards accrued yet), (amount * pool.accTokenPerShare) / ACC_TOKEN_PRECISION is zero.

This is loss of value case, but the impact value and probability is low enough, so setting the severity to medium.

Proof of Concept

Some ERC20 have low decimals:

https://github.com/d-xo/weird-erc20#low-decimals

And the least significant digit value can be high enough, for example WBTC have 8 decimals, so at the moment 1 is $0.0004:

https://etherscan.io/token/0x2260fac5e5542a773aa44fbcfedf7c193bc2c599

pool.accTokenPerShare is the accrued amount to be distributed as a reward divided by total amount staked with ACC_TOKEN_PRECISION precision:

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L289-L290

Staked amount has token decimals as shares multiplier is removed:

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L204-L205

In the current implementation reward per base token and base token amount are multiplied, which can yield zero after percentage base division:

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L218

Consider using the shares without BASE_DIVISOR removal. Also, it can be useful to introduce the minimum amount to send, so that amounts below that be stored without the attempt to send.

#0 - ankurdubey521

2022-03-30T16:30:31Z

Duplicate of #140

#1 - pauliax

2022-05-09T11:08:11Z

Similar to #140

Findings Information

🌟 Selected for report: WatchPug

Also found by: cmichel, hyh

Labels

bug
duplicate
2 (Med Risk)
sponsor disputed

Awards

560.3084 USDT - $560.31

External Links

Lines of code

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L133

Vulnerability details

Impact

Reward and base token decimals can differ, while this difference isn't accounted for in the reward amount calculations, which will lead to either missing rewards or sending the whole rewards balance to the first eligible user.

For example:

If reward is native, while base is USDC, then rewards are basically zero as 1 USDC is 1e-12 native token, so the USDC amount used as the base of reward calculation makes negligible the whole reward amount.

If reward is USDC, and base is native, the first reward amount due will most probably use the whole available balance.

Both cases will lead to losses of the rewards for the most of the LP users

Proof of Concept

LP shares saved in the LpTokenMetadata structure have the decimals of {18 + base token's decimals}:

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityProviders.sol#L288-L305

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityProviders.sol#L27

When shares are used in LiquidityFarming, their decimals are reduced to base token's, for example:

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L126-L127

However, this base token amount is then used to calculate reward amounts without decimals adjustment. In other words, rewardTokens[baseToken] is treated as if it is guaranteed to have the same decimals as baseToken:

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L133

This isn't enforced in any way, the reward token for a given base token can be arbitrary:

https://github.com/code-423n4/2022-03-biconomy/blob/main/contracts/hyphen/LiquidityFarming.sol#L104

If reward and base token's decimals differ, the reward accounting can become grossly incorrect proportionally to the decimals difference

Most common approach here is to add the token decimals variables to the contract and the decimals difference multiplier to the rewards calculations

#0 - ankurdubey521

2022-03-30T10:55:15Z

However, this base token amount is then used to calculate reward amounts without decimals adjustment. In other words, rewardTokens[baseToken] is treated as if it is guaranteed to have the same decimals as baseToken:

I believe this shouldn't be an issue since at the contract level we are only dealing with the token atoms , and the calculations are independent of their decimals

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter