Platform: Code4rena
Start Date: 06/12/2022
Pot Size: $36,500 USDC
Total HM: 16
Participants: 119
Period: 3 days
Judge: berndartmueller
Total Solo HM: 2
Id: 189
League: ETH
Rank: 110/119
Findings: 1
Award: $0.61
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: RaymondFam
Also found by: 0xdeadbeef0x, 0xhacksmithh, AkshaySrivastav, Awesome, Bnke0x0, CRYP70, HollaDieWaldfee, JC, Parth, Rahoz, Tutturu, __141345__, ahmedov, ajtra, asgeir, aviggiano, bin2chen, btk, carrotsmuggler, cccz, chaduke, cryptonue, dic0de, fatherOfBlocks, fs0c, hansfriese, jonatascm, karanctf, ladboy233, lumoswiz, martin, obront, pashov, pauliax, rvierdiiev, shark, simon135, supernova, tourist, yellowBirdy, zapaz, zaskoh
0.6136 USDC - $0.61
https://github.com/code-423n4/2022-12-escher/blob/5d8be6aa0e8634fdb2f328b99076b0d05fefab73/src/minters/FixedPrice.sol#L107-L111 https://github.com/code-423n4/2022-12-escher/blob/5d8be6aa0e8634fdb2f328b99076b0d05fefab73/src/minters/LPDA.sol#L85-L86 https://github.com/code-423n4/2022-12-escher/blob/5d8be6aa0e8634fdb2f328b99076b0d05fefab73/src/minters/LPDA.sol#L105 https://github.com/code-423n4/2022-12-escher/blob/5d8be6aa0e8634fdb2f328b99076b0d05fefab73/src/minters/OpenEdition.sol#L92
The use of the deprecated transfer() function for an address will inevitably make the transaction fail when:
This can lead to permanent lock-up of funds for both the factory feeReceiver as well as the creator of the sale.
_end()
_end()
function tries to transfer the protocol share to the feeReceiver ISaleFactory(factory).feeReceiver().transfer(address(this).balance / 20);
This will DoS the function leading to locking up the last NFT as well as all of the funds inside the contract. Thankfully, this could be mitigated by changing the feeReceiver in the factory contract, which is also the case for OpenEdition.sol.
However, if Alice were to deploy an LPDA contract and set her own saleReceiver address to a smart contract, this could lead to a longer (potentially permanent) lock-up of funds since Alice has no way of updating the saleReceiver address. The only way to resolve this issue would be to use Optional Access Lists, which would work for multisig wallets, but is not guaranteed to work for all types of smart contracts.
Foundry, manual review
I recommend using .call()
instead of .transfer()
and adding a nonReentrant modifier to any function that replaces .transfer()
with .call()
that could potentially be re-entered. One such function is finalize()
in OpenEdition.sol since it could be used to drain (almost) the entire balance to the feeReceiver() by reentering the function multiple times.
#0 - c4-judge
2022-12-10T00:29:40Z
berndartmueller marked the issue as duplicate of #99
#1 - c4-judge
2023-01-03T12:46:49Z
berndartmueller marked the issue as satisfactory