Platform: Code4rena
Start Date: 23/06/2023
Pot Size: $60,500 USDC
Total HM: 31
Participants: 132
Period: 10 days
Judge: 0xean
Total Solo HM: 10
Id: 254
League: ETH
Rank: 63/132
Findings: 5
Award: $98.98
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: georgypetrov
Also found by: CrypticShepherd, DelerRH, Kenshin, LuchoLeonel1, SpicyMeatball, bart1e, ktg, pep7siup
53.1445 USDC - $53.14
IVault in configurator defines the interface to learn the vault type to be vaultType()
, however it is getVaultType()
. This will break any call that asks for the vault type, e.g. setSafeCollateralRation()
and thus most of the protocol.
Define and use correct interface.
Other
#0 - c4-pre-sort
2023-07-08T18:36:39Z
JeffCX marked the issue as duplicate of #882
#1 - c4-judge
2023-07-28T15:36:29Z
0xean marked the issue as satisfactory
#2 - c4-judge
2023-07-28T19:43:23Z
0xean changed the severity to 2 (Med Risk)
🌟 Selected for report: hl_
Also found by: 0xRobocop, Co0nan, CrypticShepherd, DedOhWale, Iurii3, Kenshin, Musaka, OMEN, RedOneN, SpicyMeatball, Toshii, Vagner, bytes032, cccz, gs8nrv, hl_, kenta, lanrebayode77, mahdikarimi, max10afternoon, peanuts, pep7siup
5.5262 USDC - $5.53
In LybraPeUSDVaultBase's _repay()
function, fees are not correctly accounted for. This allows users to reach 0 debt even when repaying less than they owe. Repaying the full amount of getBorrowedOf()
is not possible due to integer overflow.
Amount is deducted from borrowed and circulation on this line and the following one: https://github.com/code-423n4/2023-06-lybra/blob/5d70170f2c68dbd3f7b8c0c8fd6b0b2218784ea6/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L206, not accounting for fees in the correct way. E.g. if a user only repays fees accrued, his fees will be reduced by amount
on this line https://github.com/code-423n4/2023-06-lybra/blob/5d70170f2c68dbd3f7b8c0c8fd6b0b2218784ea6/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L202 and then his borrowed will be reduced by the same amount: https://github.com/code-423n4/2023-06-lybra/blob/5d70170f2c68dbd3f7b8c0c8fd6b0b2218784ea6/contracts/lybra/pools/base/LybraPeUSDVaultBase.sol#L206
POC run against this repo: https://github.com/CrypticShepherd/lybra_tests
// POC: PeUSD accounting for repayments is incorrect function testRETHAccounting() public { vm.startPrank(owner); // deposit 2 rETH and mint 2000 PeUSD fakeRETH.approve(address(realRETHVault), 2*1e18); realRETHVault.depositAssetToMint(2*1e18, 2000*1e18); // let 100 days pass vm.warp(86400*100); uint256 debt = realRETHVault.getBorrowedOf(address(owner)); // debt should now be more than 2k due to fees assertGt(debt, 2000*1e18); // repay 1600 PeUSD only realPeUSDMainnet.approve(address(realRETHVault), 1600*1e18); realRETHVault.burn(address(owner), 1600*1e18); // debt should have decreased by 1600 (this is where it currently fails) assertEq(realRETHVault.getBorrowedOf(address(owner)), debt - 1600*1e18); vm.stopPrank(); }
Manual analysis, Foundry for POC.
Deduct fees from repaid amount.
Math
#0 - c4-pre-sort
2023-07-08T23:39:32Z
JeffCX marked the issue as duplicate of #532
#1 - c4-judge
2023-07-28T15:39:41Z
0xean marked the issue as satisfactory
#2 - c4-judge
2023-07-28T19:41:44Z
0xean changed the severity to 2 (Med Risk)
🌟 Selected for report: Musaka
Also found by: 0xhacksmithh, 0xnev, CrypticShepherd, LuchoLeonel1, T1MOH, bytes032, cccz, devival, josephdara, ktg, squeaky_cactus
29.0567 USDC - $29.06
https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L144 https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/governance/LybraGovernance.sol#L148
The votingDelay and votingPeriod variables are set to 1 and 3 blocks respectively. This will not allow for governance processes to work properly.
Manual analysis.
Increase voting delay and voting period.
Governance
#0 - c4-pre-sort
2023-07-09T14:26:39Z
JeffCX marked the issue as primary issue
#1 - c4-pre-sort
2023-07-11T21:26:19Z
JeffCX marked the issue as duplicate of #268
#2 - c4-judge
2023-07-28T15:43:53Z
0xean marked the issue as satisfactory
🌟 Selected for report: bytes032
Also found by: 0xMAKEOUTHILL, 0xgrbr, 0xkazim, 0xnacho, Arz, Co0nan, CrypticShepherd, Cryptor, HE1M, Iurii3, LaScaloneta, LokiThe5th, LuchoLeonel1, MrPotatoMagic, Musaka, Qeew, RedTiger, SovaSlava, Toshii, Vagner, a3yip6, azhar, bart1e, devival, hl_, jnrlouis, kutugu, peanuts, pep7siup, qpzm, smaul
1.3247 USDC - $1.32
rETH exchange rate is read from getExchangeRate()
, not getExchangeRatio()
. Current code will not work.
Source: https://etherscan.io/token/0xae78736Cd615f374D3085123A210448E74Fc6393#readContract
Use correct interface.
Other
#0 - c4-pre-sort
2023-07-08T23:38:35Z
JeffCX marked the issue as duplicate of #704
#1 - c4-pre-sort
2023-07-27T20:40:18Z
JeffCX marked the issue as not a duplicate
#2 - c4-pre-sort
2023-07-27T20:40:31Z
JeffCX marked the issue as duplicate of #27
#3 - c4-judge
2023-07-28T17:14:12Z
0xean changed the severity to 2 (Med Risk)
#4 - c4-judge
2023-07-28T17:15:39Z
0xean marked the issue as satisfactory
🌟 Selected for report: bytes032
Also found by: 0xMAKEOUTHILL, 0xgrbr, 0xkazim, 0xnacho, Arz, Co0nan, CrypticShepherd, Cryptor, HE1M, Iurii3, LaScaloneta, LokiThe5th, LuchoLeonel1, MrPotatoMagic, Musaka, Qeew, RedTiger, SovaSlava, Toshii, Vagner, a3yip6, azhar, bart1e, devival, hl_, jnrlouis, kutugu, peanuts, pep7siup, qpzm, smaul
1.3247 USDC - $1.32
WbETH exchange rate is read from exchangeRate()
, not exchangeRatio()
. Current code will not work.
Source: https://etherscan.io/address/0xa2e3356610840701bdf5611a53974510ae27e2e1#readProxyContract
Use correct interface.
Other
#0 - c4-pre-sort
2023-07-08T23:37:23Z
JeffCX marked the issue as duplicate of #27
#1 - c4-judge
2023-07-28T17:14:13Z
0xean changed the severity to 2 (Med Risk)
#2 - c4-judge
2023-07-28T17:15:37Z
0xean marked the issue as satisfactory
🌟 Selected for report: 0xnev
Also found by: 0xRobocop, 0xbrett8571, 0xkazim, 0xnacho, 3agle, 8olidity, ABAIKUNANBAEV, Bauchibred, Co0nan, CrypticShepherd, D_Auditor, DelerRH, HE1M, Iurii3, Kaysoft, MrPotatoMagic, RedOneN, RedTiger, Rolezn, SanketKogekar, Sathish9098, Timenov, Toshii, Vagner, bart1e, bytes032, codetilda, devival, halden, hals, kutugu, m_Rassska, naman1778, nonseodion, seth_lawson, solsaver, squeaky_cactus, totomanov, y51r, yudan, zaevlad
9.931 USDC - $9.93
The LBR token implementation refers to the configurator, which will, based on my current my understanding, only be deployed on Ethereum mainnet for V2.
With no configurator, mint()
and burn()
in the LBR contract on Arbitrum will always revert, as the tokenMiner
check at the beginning of those functions cannot be done.
Filing this as a QA finding as it's easy to work around and doesn't seem to cause any bigger issues, but still appears quite inelegant.
Instead of Copy-Pasting some OFTV2 implementation code into LBR.sol, PeUSD.sol and PeUSDMainnetStableVision.sol, it would be cleaner to base those contracts off OFTV2 given here: https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/oft/v2/OFTV2.sol
This check is performed in _mint() of the OZ ERC20 implementation (observe that burn() in the same contract doesn't check for the 0 address).
Interface spec declares "amount of token":
But actual value given is "amount of shares":
Function doesn't contain a return statement: https://github.com/code-423n4/2023-06-lybra/blob/7b73ef2fbb542b569e182d9abf79be643ca883ee/contracts/lybra/token/EUSD.sol#L411
#0 - c4-pre-sort
2023-07-27T16:40:22Z
JeffCX marked the issue as high quality report
#1 - c4-judge
2023-07-27T23:56:48Z
0xean marked the issue as grade-b
#2 - c4-sponsor
2023-07-29T09:52:00Z
LybraFinance marked the issue as sponsor confirmed