Platform: Code4rena
Start Date: 10/05/2022
Pot Size: $50,000 USDC
Total HM: 13
Participants: 100
Period: 5 days
Judge: HardlyDifficult
Total Solo HM: 1
Id: 122
League: ETH
Rank: 32/100
Findings: 4
Award: $113.11
π Selected for report: 0
π Solo Findings: 0
π Selected for report: 0x1337
Also found by: 0x52, 0xDjango, 0xsanson, BondiPestControl, BowTiedWardens, GimelSec, IllIllI, MaratCerby, MiloTruck, PPrieditis, TrungOre, VAD37, WatchPug, berndartmueller, cccz, dipp, hake, hickuphh3, horsefacts, hubble, minhquanym, reassor, shenwilly, smiling_heretic
10.8874 USDC - $10.89
Judge has assessed an item in Issue #95 as Medium risk. The relevant finding follows:
Incompatability with deflationary / fee-on-transfer tokens Function Cally.createVault function takes a tokenIdOrAmount parameter but this parameter is not the actual transferred amount for fee-on-transfer / deflationary (or other rebasing) tokens in case tokenType = ERC20 Impact The actual deposited amount might be lower than the specified depositAmount of the function parameter. And when users exercise or withdraw they not only receive less than expected amount but also take funds of other vaults with the same vault.token too, causes loss of funds. Proof-of-concept https://github.com/code-423n4/2022-05-cally/blob/1849f9ee12434038aa80753266ce6a2f2b082c59/contracts/src/Cally.sol#L200 https://github.com/code-423n4/2022-05-cally/blob/1849f9ee12434038aa80753266ce6a2f2b082c59/contracts/src/Cally.sol#L296 https://github.com/code-423n4/2022-05-cally/blob/1849f9ee12434038aa80753266ce6a2f2b082c59/contracts/src/Cally.sol#L345 Recommended Mitigation Steps Transfer the tokens first and compare pre-/after token balances to compute the actual amount.
#0 - HardlyDifficult
2022-06-06T00:30:27Z
16.9712 USDC - $16.97
https://github.com/code-423n4/2022-05-cally/blob/1849f9ee12434038aa80753266ce6a2f2b082c59/contracts/src/Cally.sol#L295 https://github.com/code-423n4/2022-05-cally/blob/1849f9ee12434038aa80753266ce6a2f2b082c59/contracts/src/Cally.sol#L344
Cally.exercise()
and Cally.withdraw()
, ERC721 token is sent to msg.sender
and the transferFrom
keyword is used instead of safeTransferFrom
. If msg.sender
is a contract and is not aware of incoming ERC721 tokens, the sent tokens could be locked forevertransferFrom
to safeTransferFrom
.#0 - outdoteth
2022-05-15T20:45:11Z
use safeTransferFrom to prevent stuck NFTs: https://github.com/code-423n4/2022-05-cally-findings/issues/38
π Selected for report: hubble
Also found by: 0x1337, 0x1f8b, 0x4non, 0xDjango, 0xf15ers, 0xsanson, 242, Aits, AlleyCat, Bludya, BondiPestControl, BouSalman, BowTiedWardens, CertoraInc, Cityscape, Czar102, FSchmoede, Funen, Hawkeye, IllIllI, JDeryl, Kenshin, Kumpa, MaratCerby, MiloTruck, Picodes, Ruhum, TrungOre, VAD37, WatchPug, Waze, antonttc, bobirichman, catchup, cccz, cryptphi, csanuragjain, delfin454000, dipp, dirk_y, djxploit, eccentricexit, ellahi, fatherOfBlocks, hake, hansfriese, hickuphh3, horsefacts, hyh, jah, joestakey, mics, minhquanym, pedroais, pmerkleplant, radoslav11, reassor, rfa, robee, seanamani, shenwilly, shung, sikorico, sorrynotsorry, sseefried, z3s
54.9324 USDC - $54.93
Cally.createVault
function takes a tokenIdOrAmount
parameter but this parameter is not the actual transferred amount for fee-on-transfer / deflationary (or other rebasing) tokens in case tokenType = ERC20
exercise
or withdraw
they not only receive less than expected amount but also take funds of other vaults with the same vault.token
too, causes loss of funds.Cally.createVault()
function, vaultIndex += 2
is done before assigning it to vaultId
. So vaultId
will start from 3 and optionId
will start from 4. There will not have tokenId = 0
or tokenId = 1
vaultIndex
to vaultId
before add 2.vaultId = vaultIndex; vaultIndex += 2;
#0 - outdoteth
2022-05-16T16:27:00Z
this can be bumped to medium severity:
#1 - HardlyDifficult
2022-05-30T19:00:18Z
Moved fee on transfer report to https://github.com/code-423n4/2022-05-cally-findings/issues/326
π Selected for report: IllIllI
Also found by: 0v3rf10w, 0x1f8b, 0x4non, 0xDjango, 0xNazgul, 0xf15ers, 0xkatana, 0xsanson, Bludya, BowTiedWardens, CertoraInc, Cityscape, DavidGialdi, FSchmoede, Fitraldys, Funen, Hawkeye, Kenshin, MadWookie, MaratCerby, MiloTruck, Picodes, RagePit, Tadashi, TerrierLover, TomFrenchBlockchain, VAD37, WatchPug, Waze, _Adam, antonttc, bobirichman, catchup, defsec, delfin454000, djxploit, ellahi, fatherOfBlocks, gzeon, hake, hansfriese, hickuphh3, horsefacts, ignacio, joestakey, jonatascm, mics, minhquanym, oyc_109, pmerkleplant, rfa, robee, rotcivegaf, samruna, shung, sikorico, simon135, z3s
30.3165 USDC - $30.32
storage
when read only 1 field from a struct can save gasIn Cally.getPremium
function, we only need 1 field from vault
which is vault.premiumIndex
but a whole Vault
is loaded to memory.
We can save gas by using storage
instead of memory
storage
instead of memory
in case you not need all the struct data.In Cally.buyOption
and Cally.exercise
function, we only modify one or two data fields of vault
but we write a whole data struct to storage, including non-changed data.
And since write to storage is one of the most expensive operation. We should save gas by only writing changed data to storage.
_vaults[vaultId].isExercised = true;