Platform: Code4rena
Start Date: 05/07/2023
Pot Size: $390,000 USDC
Total HM: 136
Participants: 132
Period: about 1 month
Judge: LSDan
Total Solo HM: 56
Id: 261
League: ETH
Rank: 20/132
Findings: 13
Award: $3,585.64
π Selected for report: 2
π Solo Findings: 1
π Selected for report: ItsNio
Also found by: ItsNio, SaeedAlipoor01988
1163.4744 USDC - $1,163.47
The value of utilization is calculated before Accrue interest and using the invalid (out of date) value of _totalBorrow.elastic.
The Utilization value is calculated by the formula below, at line SGLCommon.sol#L61.
utilization = fullAssetAmount == 0 ? 0 : (uint256(_totalBorrow.elastic) * UTILIZATION_PRECISION) / fullAssetAmount;
The problem is that, in the Accrue interest block, value of _totalBorrow.elastic, is updated at line SGLCommon.sol#L104 :
// Accrue interest extraAmount = (uint256(_totalBorrow.elastic) * _accrueInfo.interestPerSecond * elapsedTime) / 1e18; _totalBorrow.elastic += uint128(extraAmount);
And then, at line SGLCommon.sol#L112, interest rate get updated using the Utilization value :
if (utilization < minimumTargetUtilization) { uint256 underFactor = ((minimumTargetUtilization - utilization) * FACTOR_PRECISION) / minimumTargetUtilization; uint256 scale = interestElasticity + (underFactor * underFactor * elapsedTime); _accrueInfo.interestPerSecond = uint64( (uint256(_accrueInfo.interestPerSecond) * interestElasticity) / scale ); if (_accrueInfo.interestPerSecond < minimumInterestPerSecond) { _accrueInfo.interestPerSecond = minimumInterestPerSecond; // 0.25% APR minimum } } else if (utilization > maximumTargetUtilization) { uint256 overFactor = ((utilization - maximumTargetUtilization) * FACTOR_PRECISION) / fullUtilizationMinusMax; uint256 scale = interestElasticity + (overFactor * overFactor * elapsedTime); uint256 newInterestPerSecond = (uint256( _accrueInfo.interestPerSecond ) * scale) / interestElasticity; if (newInterestPerSecond > maximumInterestPerSecond) { newInterestPerSecond = maximumInterestPerSecond; // 1000% APR maximum } _accrueInfo.interestPerSecond = uint64(newInterestPerSecond); }
Manually
The value of utilization, should get updated before line SGLCommon.sol#L112.
Other
#0 - c4-pre-sort
2023-08-05T00:08:11Z
minhquanym marked the issue as duplicate of #1057
#1 - c4-judge
2023-09-12T16:44:43Z
dmvt marked the issue as satisfactory
π Selected for report: GalloDaSballo
Also found by: 0xfuje, KIntern_NA, SaeedAlipoor01988, gizzy
101.7807 USDC - $101.78
https://github.com/Tapioca-DAO/tapioca-periph-audit/blob/023751a4e987cf7c203ab25d3abba58f7344f213/contracts/Swapper/UniswapV3Swapper.sol#L38 https://github.com/Tapioca-DAO/tapioca-periph-audit/blob/023751a4e987cf7c203ab25d3abba58f7344f213/contracts/Swapper/UniswapV3Swapper.sol#L184 https://github.com/Tapioca-DAO/tapioca-yieldbox-strategies-audit/blob/05ba7108a83c66dada98bc5bc75cf18004f2a49b/contracts/stargate/StargateSwapperV3.sol#L29
Hardcoded UNISWAP_FEE can reduce significantly the possibilities and will lead to non optimal routes.
Uniswap v3 introduces multiple pools for each token pair, each with a different swapping fee. Liquidity providers may initially create pools at three fee levels: 0.05%, 0.30%, and 1%. https://info.uniswap.org/pairs#/pools
For example, for USDT / WETH, the optimal route is currently USDT -> USDC and USDC -> ETH with USDT -> ETH. The pool USDT / ETH with 0.3% fees is tiny compared to the ones with 0.05 %, and the pool USDC / ETH with 0.3% fees is tiny compared to the ones with 0.05 %. Therefore, using the current implementation would create a significant loss of revenue.
Manually
You may want to add the possibility to do the swaps through an efficient aggregator like 1Inch or Paraswap, it will be way more optimal.
Uniswap
#0 - c4-pre-sort
2023-08-06T08:19:41Z
minhquanym marked the issue as low quality report
#1 - minhquanym
2023-08-06T08:19:43Z
Consider QA
#2 - c4-pre-sort
2023-08-06T16:25:44Z
minhquanym marked the issue as primary issue
#3 - c4-judge
2023-09-19T18:13:57Z
dmvt marked issue #1553 as primary and marked this issue as a duplicate of 1553
#4 - c4-judge
2023-09-19T18:14:06Z
dmvt marked the issue as satisfactory
π Selected for report: GalloDaSballo
Also found by: 0xrugpull_detector, GalloDaSballo, SaeedAlipoor01988, kaden, ladboy233, unsafesol
76.3356 USDC - $76.34
The value of maxLoss to withdraw from yearn vault is hard-coded to 0. because of below assert, there is a possibility that withdrawal from yearn vaults is not possible.
The maxLoss is The maximum acceptable loss to sustain on withdrawal. defaults value for yearn vaults is 0.01%. If a loss is specified, up to that amount of shares may be burnt to cover losses on withdrawal. there is a assert check in the Vault.vy contract as loss protection. this loss protection is put in place to revert if losses from withdrawing are more than what is considered acceptable.
# NOTE: This loss protection is put in place to revert if losses from # withdrawing are more than what is considered acceptable. assert totalLoss <= maxLoss * (value + totalLoss) / MAX_BPS
Tapioca is hard-coded the maxLoss to 0 in the YearnStrategy.sol contract. that means In the process of withdrawing from yearn vault, totalLoss should be 0 and this can be almost impossible and lead to the locking of fund in yearn vault. https://github.com/Tapioca-DAO/tapioca-yieldbox-strategies-audit/blob/05ba7108a83c66dada98bc5bc75cf18004f2a49b/contracts/yearn/YearnStrategy.sol#L145
vault.withdraw(toWithdraw, address(this), 0);
But if 0 mean Yearn default maxLoss, you should know, it is 0.01%. In certain cases where the amount to be withdrawn is large enough, the Yearn withdrawal will revert. in a situation where the market is fluctuating, users' funds can be locked in the yearn vault.
Manually
Allow the user to enter the value of maxLoss.
DoS
#0 - c4-pre-sort
2023-08-05T08:53:53Z
minhquanym marked the issue as primary issue
#1 - minhquanym
2023-08-05T08:58:24Z
Consider Medium
#2 - c4-sponsor
2023-08-14T15:24:16Z
0xRektora marked the issue as sponsor confirmed
#3 - c4-judge
2023-09-13T09:07:52Z
dmvt changed the severity to 2 (Med Risk)
#4 - c4-judge
2023-09-13T09:08:31Z
dmvt marked issue #1456 as primary and marked this issue as a duplicate of 1456
#5 - c4-judge
2023-09-13T09:08:42Z
dmvt marked the issue as satisfactory
π Selected for report: windhustler
Also found by: SaeedAlipoor01988, bin2chen, peakbolt, rvierdiiev
50.8904 USDC - $50.89
https://github.com/Tapioca-DAO/tapiocaz-audit/blob/bcf61f79464cfdc0484aa272f9f6e28d5de36a8f/contracts/tOFT/modules/BaseTOFTOptionsModule.sol#L221 https://github.com/LayerZero-Labs/solidity-examples/blob/34cf25c06f5cf26fdbef80e0d693c77552aaa2db/contracts/token/oft/v2/BaseOFTV2.sol#L17
Transactions sent to LZ will get revert.
When sending messages using the LayerZero architecture, native tokens must be supplied to cover the cost of delivering the message at the receiving chain. the OFTV2.sendFrom function is payable function and get native token as gas fee.
function sendFrom(address _from, uint16 _dstChainId, bytes32 _toAddress, uint _amount, LzCallParams calldata _callParams) public payable virtual override { _send(_from, _dstChainId, _toAddress, _amount, _callParams.refundAddress, _callParams.zroPaymentAddress, _callParams.adapterParams); }
In the BaseTOFTOptionsModule.sol.exerciseInternal function, sendFrom is called without passing value.
if (tapSendData.withdrawOnAnotherChain) { ISendFrom(tapSendData.tapOftAddress).sendFrom( address(this), tapSendData.lzDstChainId, LzLib.addressToBytes32(from), tapAmount, ISendFrom.LzCallParams({ refundAddress: payable(from), zroPaymentAddress: tapSendData.zroPaymentAddress, adapterParams: LzLib.buildDefaultAdapterParams( tapSendData.extraGas ) }) );
Same issue is when Balancer.sol calls the StargateRouter's swap() which also requires value. https://stargateprotocol.gitbook.io/stargate/developers/how-to-swap
https://github.com/Tapioca-DAO/tapiocaz-audit/blob/bcf61f79464cfdc0484aa272f9f6e28d5de36a8f/contracts/Balancer.sol#L322 https://github.com/Tapioca-DAO/tapiocaz-audit/blob/bcf61f79464cfdc0484aa272f9f6e28d5de36a8f/contracts/Balancer.sol#L288
Manually
Pass value for ISendFrom(tapSendData.tapOftAddress).sendFrom in BaseTOFTOptionsModule.sol.exerciseInternal.
Error
#0 - c4-pre-sort
2023-08-06T09:31:45Z
minhquanym marked the issue as duplicate of #1199
#1 - c4-judge
2023-09-21T11:33:16Z
dmvt changed the severity to 2 (Med Risk)
#2 - c4-judge
2023-09-21T11:38:00Z
dmvt marked the issue as partial-50
46.3738 USDC - $46.37
Borrowers can't repay when the system is paused, so they must pay more interest for the paused period.
Borrower can repay the loan using Singularity.sol#L296.repay function. But this function doesn't work when the system is paused and Borrowers have no way to avoid it.
function repay( address from, address to, bool skim, uint256 part ) public notPaused allowedBorrow(from, part) returns (uint256 amount) { updateExchangeRate(); _accrue(); amount = _repay(from, to, skim, part); }
The Market.sol#L245.updatePause function, is using for change pause mode and only conservator role can use it.as i see, conservator account is EAO.
function updatePause(bool val) external { require(msg.sender == conservator, "Market: unauthorized"); require(val != paused, "Market: same state"); emit PausedUpdated(paused, val); paused = val; } /// @dev conservator can pause/unpause the contract address public conservator;
The role of conservator is determined by the owner. So conservator can be the owner himself. https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/Market.sol#L187
There is no assurance that the conservator would pause the community for a while to get more interest.
Manually
Change approach to make repay function work for pause period or modify the interest calculation formula not to add interest for the pause period.
Other
#0 - c4-pre-sort
2023-08-04T23:39:26Z
minhquanym marked the issue as primary issue
#1 - c4-pre-sort
2023-08-04T23:42:38Z
minhquanym marked the issue as duplicate of #1169
#2 - c4-judge
2023-09-29T19:13:18Z
dmvt marked the issue as satisfactory
π Selected for report: zzzitron
Also found by: 0xG0P1, 0xRobocop, RedOneN, SaeedAlipoor01988, bin2chen, cergyk, rvierdiiev, unsafesol
37.0991 USDC - $37.10
https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLLiquidation.sol#L294 https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/Market.sol#L53
In the long run, the value of Market.sol#L53.totalCollateralShare ( total collateral supplied ) increases infinitely.
In the liquidation process, two methods play an essential role. SGLLiquidation.sol#L97._orderBookLiquidation()
and SGLLiquidation.sol#L294._liquidateUser()
.
The contract will call closedLiquidation()
function if not liquidationQueue
exists or no liquidationQueue bid avail exists. function _liquidateUser()
is called inside function closedLiquidation()
.
function _closedLiquidation( address[] calldata users, uint256[] calldata maxBorrowParts, ISwapper swapper, uint256 _exchangeRate, bytes calldata swapData ) private { uint256 liquidatedCount = 0; for (uint256 i = 0; i < users.length; i++) { address user = users[i]; if (!_isSolvent(user, _exchangeRate)) { liquidatedCount++; _liquidateUser( user, maxBorrowParts[i], swapper, _exchangeRate, swapData ); } } require(liquidatedCount > 0, "SGL: no users found"); }
When the user fund is liquidated, three general variables in the project must be updated. In the _orderBookLiquidation()
, these three variables are updated as follows, totalCollateralShare and totalBorrow :
_totalBorrow.elastic -= uint128(allBorrowAmount); _totalBorrow.base -= uint128(allBorrowPart); totalBorrow = _totalBorrow; totalCollateralShare -= allCollateralShare;
Briefly, the variable totalCollateralShare
is defined as the value of total collateral supplied in the protocol. In the liquidation process, the user's collateral is sold for borrowed asset. so the amount of totalCollateralShare
should get reduced to the amount of collateral sold in the form of shares
. you can see the conversion example below :
uint256 amountWithBonus = borrowAmount + @ audit : how much asset amount (borrowAmount * liquidationMultiplier) / FEE_PRECISION; uint256 collateralShare = yieldBox.toShare( @audit : convert asset to collateral share collateralId, (amountWithBonus * _exchangeRate) / EXCHANGE_RATE_PRECISION, false ); userCollateralShare[user] -= collateralShare; @audit : subtract collateral share from user collateral share // @audit : Keep local totals allCollateralShare += collateralShare; allBorrowAmount += borrowAmount; allBorrowPart += borrowPart; } } @audit : update local totals and sync storage total _totalBorrow.elastic -= uint128(allBorrowAmount); _totalBorrow.base -= uint128(allBorrowPart); totalBorrow = _totalBorrow; totalCollateralShare -= allCollateralShare;
The problem is that, in the SGLLiquidation.sol#L294._liquidateUser()
and SGLLiquidation.sol#L204._updateBorrowAndCollateralShare()
function, the value of totalBorrow is updated but value of totalCollateralShare
doesn't get update. function _updateBorrowAndCollateralShare()
is called inside function _liquidateUser()
.
uint256 amountWithBonus = borrowAmount + (borrowAmount * liquidationMultiplier) / FEE_PRECISION; collateralShare = yieldBox.toShare( collateralId, (amountWithBonus * _exchangeRate) / EXCHANGE_RATE_PRECISION, false ); if (collateralShare > userCollateralShare[user]) { collateralShare = userCollateralShare[user]; } userCollateralShare[user] -= collateralShare; require(borrowAmount != 0, "SGL: solvent"); totalBorrow.elastic -= uint128(borrowAmount); totalBorrow.base -= uint128(borrowPart);
Because of this, in the long run, the value of Market.sol#L53.totalCollateralShare ( total collateral supplied ) increases infinitely.
Manually
Update totalCollateralShare
value in the _liquidateUser
function same as in the _orderBookLiquidation
function.
Other
#0 - c4-pre-sort
2023-08-05T01:11:51Z
minhquanym marked the issue as primary issue
#1 - c4-pre-sort
2023-08-05T01:14:03Z
minhquanym marked the issue as duplicate of #1040
#2 - c4-judge
2023-09-12T16:59:20Z
dmvt changed the severity to 2 (Med Risk)
#3 - c4-judge
2023-09-12T17:06:39Z
dmvt marked the issue as satisfactory
π Selected for report: SaeedAlipoor01988
Also found by: kaden
453.755 USDC - $453.76
Please check PoC.
Curve allows Curve LP token holders to stake their position to receive CRV and potentially other bonus reward tokens. but in TricryptoNativeStrategy contract, it is assumed that only CRV token is available as reward. used lpGauge.claimable_tokens to get the amount of currently mintable CRV from gauge. accounting for rewards, from lpGauge contract, has been done for CRV.
uint256 claimable = lpGauge.claimable_tokens(address(this)); if (claimable > 0) { uint256 crvBalanceBefore = rewardToken.balanceOf(address(this)); minter.mint(address(lpGauge)); uint256 crvBalanceAfter = rewardToken.balanceOf(address(this)); if (crvBalanceAfter > crvBalanceBefore) { uint256 crvAmount = crvBalanceAfter - crvBalanceBefore; ISwapper.SwapData memory swapData = swapper.buildSwapData( address(rewardToken), address(wrappedNative), crvAmount, 0, false, false ); uint256 calcAmount = swapper.getOutputAmount(swapData, ""); uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5% swapper.swap(swapData, minAmount, address(this), ""); uint256 queued = wrappedNative.balanceOf(address(this)); _addLiquidityAndStake(queued); emit AmountDeposited(queued); } }
Based on the Curve docs and LiquidityGaugeV3.vy smart contract, it's possible that more reward tokens (contracts) get added to the lpGauge contract:
In function _withdraw, withdrawal from lpGauge contract is done as follows. this function have an optional argument _claim_rewards, which when set to True will claim any pending rewards.
lpGauge.withdraw(lpBalance, true);
The value of _claim_rewards is true and causes rewards to be collected to the TricryptoNativeStrategy contract, but no management has been done on these pending rewards and causes these rewards to be lost.
Manually
And you can querying Reward Information by below function's : https://curve.readthedocs.io/dao-gauges.html#querying-reward-information
Invalid Validation
#0 - c4-pre-sort
2023-08-07T02:06:40Z
minhquanym marked the issue as primary issue
#1 - minhquanym
2023-08-07T02:06:45Z
Similar #162
#2 - c4-sponsor
2023-09-06T07:58:59Z
cryptotechmaker (sponsor) confirmed
#3 - c4-judge
2023-09-19T14:09:57Z
dmvt marked the issue as selected for report
π Selected for report: dirk_y
Also found by: KIntern_NA, SaeedAlipoor01988, ltyu
141.3621 USDC - $141.36
Using a wrong decimal number on the exchange rate could cause incorrect pricing.
The BigBang contract assumes the exchange rates returned from SGOracle.sol have 18 decimals, while, however, which is not true. below is code for get price based on the USDT pool and USDT price from chainlink :
contract BaseContract {
//100181073 function GetP() public pure returns(uint) { return (23090372827983 * uint256(99977000)) / 23043336774138; }
}
Reurned price is with 9 decimals. Using a wrong decimal number on the exchange rate could cause incorrect pricing.
Manually
Based on the pool decimals and UNDERLYING oracle decimals, first, scale decimals of exchange rate to 18.
Decimal
#0 - c4-pre-sort
2023-08-06T01:06:14Z
minhquanym marked the issue as duplicate of #188
#1 - c4-judge
2023-09-29T18:15:05Z
dmvt marked the issue as satisfactory
π Selected for report: SaeedAlipoor01988
1008.3444 USDC - $1,008.34
https://github.com/Tapioca-DAO/tapioca-periph-audit/blob/023751a4e987cf7c203ab25d3abba58f7344f213/contracts/Swapper/UniswapV3Swapper.sol#L38 https://github.com/Tapioca-DAO/tapioca-periph-audit/blob/023751a4e987cf7c203ab25d3abba58f7344f213/contracts/Swapper/UniswapV3Swapper.sol#L61 https://github.com/Tapioca-DAO/tapioca-periph-audit/blob/023751a4e987cf7c203ab25d3abba58f7344f213/contracts/Swapper/UniswapV3Swapper.sol#L96 https://github.com/Tapioca-DAO/tapioca-yieldbox-strategies-audit/blob/05ba7108a83c66dada98bc5bc75cf18004f2a49b/contracts/stargate/StargateSwapperV3.sol#L29
If the UniswapV3Swapper.sol.poolFee is set to the value of the pool that is not yet deployed, an attacker can deploy & initialize the pool with his desired price, then the oracle will get the rate from that manipulated pool.
In the UniswapV3Swapper.sol, value of poolFee is coded to 3000 and is changeable by UniswapV3Swapper.sol.setPoolFee method. this value is used in the UniswapV3Factory to find pool and get best rate for swap. because uniswapv3 is using the fee value to find the address of a pool.
address pool = factory.getPool(tokenIn, tokenOut, poolFee); (int24 tick, ) = OracleLibrary.consult(pool, 60); amountIn = OracleLibrary.getQuoteAtTick( tick, uint128(amountOut), tokenOut, tokenIn );
Uniswap v3 introduces multiple pools for each token pair, each with a different swapping fee. Liquidity providers may initially create pools at three fee levels: 0.05%, 0.30%, and 1%. More fee levels may be added by UNI governance, e.g. the 0.01% fee level added by this governance proposal in November 2021, as executed here. According to https://docs.uniswap.org/concepts/protocol/fees#pool-fees-tiers
an attacker could check the defaultFee of the StargateSwapperV3.sol and then check what tokens tapioca markets have in it's balance, if there is a right match where the defaultFee for a token pair does not exist, attacker could deploy and initialized it with his desired price.
https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Factory.sol#L35 https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/UniswapV3Factory.sol#L20
Manually
recommend the protocol valid the pool exists with token0 and token1 and fee setting before using the oracle when deploying the price oracle contract.
Invalid Validation
#0 - c4-pre-sort
2023-08-05T15:55:37Z
minhquanym marked the issue as primary issue
#1 - c4-sponsor
2023-08-18T20:01:36Z
0xRektora marked the issue as disagree with severity
#2 - 0xRektora
2023-08-18T20:06:48Z
Severity is right, plugin won't undo, should be medium
.
#3 - c4-sponsor
2023-08-18T20:06:56Z
0xRektora marked the issue as sponsor confirmed
#4 - c4-judge
2023-09-20T19:59:30Z
dmvt marked the issue as satisfactory
#5 - c4-judge
2023-10-02T14:25:18Z
dmvt marked the issue as selected for report
π Selected for report: 0xWaitress
Also found by: Ack, BPZ, Breeje, LosPollosHermanos, Madalad, Nyx, Ruhum, SaeedAlipoor01988, ayeslick, c7e7eff, carrotsmuggler, cergyk, dirk_y, hack3r-0m, iglyx, kaden, kodyvim, kutugu, ladboy233, ltyu, mojito_auditor, n1punp, rvierdiiev, unsafesol, zzzitron
2.1417 USDC - $2.14
https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/bigBang/BigBang.sol#L603 https://github.com/Tapioca-DAO/tapioca-bar-audit/blob/2286f80f928f41c8bc189d0657d74ba83286c668/contracts/markets/singularity/SGLLiquidation.sol#L337
In the BigBang.sol._liquidateUser, the DEX transaction to swap the collateralShare into Asset can be done without slippage protection and at a loss.
The BigBang.sol.liquidate function, get collateralToAssetSwapData as input from users. In the _liquidateUser function, minAssetMount value is extracted from collateralToAssetSwapData. as you can see, the value of minAssetMount by default is 0, if the user has also entered the value of minAssetMount as zero, the same default value (*** 0 value for slippage ***) will be used in the swap transaction.
uint256 minAssetMount = 0; if (_dexData.length > 0) { minAssetMount = abi.decode(_dexData, (uint256)); } swapper.swap(swapData, minAssetMount, address(this), "");
As a result, the swap transaction will be done with zero value for slippage, which can cause the contract to receive asset with a lower value than the collateral given to the user.
Same is happening in the SGLLiquidation.sol._liquidateUser function. SGLLiquidation.sol._liquidateUser function, get dexData as input from users. In the _liquidateUser, minAssetAmount value is extracted from dexData. as you can see, the value of minAssetAmount by default is 0, if the user has also entered the value of minAssetAmount as zero, the same default value (0) will be used in the swap transaction.
uint256 minAssetAmount = 0; if (dexData.length > 0) { minAssetAmount = abi.decode(dexData, (uint256)); } ISwapper.SwapData memory swapData = swapper.buildSwapData( collateralId, assetId, 0, collateralShare, true, true ); swapper.swap(swapData, minAssetAmount, address(this), "");
As a result, DEX transaction to swap the collateralShare into Asset can be done without slippage protection and at a loss.
Manually
Add slippage protection.
Uniswap
#0 - c4-pre-sort
2023-08-05T12:55:45Z
minhquanym marked the issue as low quality report
#1 - c4-pre-sort
2023-08-05T14:40:38Z
minhquanym marked the issue as primary issue
#2 - c4-pre-sort
2023-08-08T18:53:05Z
minhquanym marked the issue as remove high or low quality report
#3 - c4-sponsor
2023-08-14T22:41:09Z
0xRektora marked the issue as disagree with severity
#4 - 0xRektora
2023-08-14T22:45:56Z
Valid, should be marked as medium
. Liquidator has more incentives to cooperate to get his reward rather than using wrong values.
#5 - c4-sponsor
2023-08-15T05:29:17Z
cryptolyndon marked the issue as sponsor disputed
#6 - c4-sponsor
2023-08-15T05:33:24Z
cryptolyndon marked the issue as sponsor confirmed
#7 - c4-judge
2023-09-13T09:29:36Z
dmvt changed the severity to 2 (Med Risk)
#8 - dmvt
2023-09-13T09:32:03Z
I agree with the sponsor on severity. Several external factors are involved.
#9 - c4-judge
2023-09-13T09:32:47Z
dmvt marked the issue as selected for report
#10 - c4-judge
2023-09-19T11:53:45Z
dmvt marked the issue as duplicate of #245
#11 - c4-judge
2023-10-02T11:45:23Z
dmvt marked the issue as not selected for report
#12 - c4-judge
2023-10-02T14:01:49Z
dmvt marked the issue as satisfactory