https://code4rena.com/reports/2022-09-quickswap
Code4rena
Code4rena is a competitive audit platform that finds more high-severity vulnerabilities, more quickly than any other auditing method.
code4rena.com
https://github.com/code-423n4/2022-09-quickswap
GitHub - code-423n4/2022-09-quickswap
Contribute to code-423n4/2022-09-quickswap development by creating an account on GitHub.
github.com
[H-01] Malicious users can provide liquidity on behalf of others to keep others in the liquidity cooldown
AlgebraPool컨트랙트에서 user가 mint()를 통해서 liquidity를 제공할 때, lastLiquidityAddTimestamp는 현재시간으로 업데이트된다.
user가 burn()을 통해서 liquidity를 제거하고 난 후에 현재시간이 lastLiquidityAddTimestamp + _liquidityCooldown보다 작으면 트랜잭션은 revert()될 것이다.
liquidityCooldown의 최대값은 1 day이다.
그러나 mint()에서 user는 다른 사람을 대신해서 liquidity를 제공할 수 있다. 그것은 악의적인 유저가 계속해서 다른 유저의 liquidity cooldown을 영원히 유지할 수 있다는 것이다. 다른 유저를 대신해 liquidity를 조금씩 제공함으로써.
따라서 다른 유저가 liquidity를 제거하는 것을 막아야한다.
user가 자신만 liquidity를 제공하도록 허용하거나 liquidityCooldown을 0으로 설정하는 것을 생각해야 한다.
[M-01] Flashloan users can be forced to pay higher fees than expected
AlgebraPool.flash() 여기서
블록에서 첫 번째 스왑이 일어나면, 이 스왑은 해당 블록 내에서 이루어지는 모든 다른 활동에 적용되는 수수료, 특히 flashloans에 대한 수수료까지 설정한다. 만약 flashloan 진행 전에 동일한 블록 내에서 다른 스왑이 발생했다면, flashloan에 적용되는 수수료가 예상과 달라질 수 있으며, 경우에 따라 크게 달라질 수도 있다. 이러한 상황을 이용해 공격자는 먼저 수수료를 높이는 스왑을 실행함으로써 플래시론 호출을 선점할 수 있다. 이는 사전 스왑의 상태에 따라 다르지만, 유동성 공급자는 수익을 극대화하기 위해 풀을 지속적으로 모니터링할 강한 동기를 가지게 된다.
그렇기 때문에 두 가지 가능한 해결책이 있다.
첫 번째는 플래시론 사용자가 지불할 최대 수수료를 지정할 수 있게 하는 것이다.
두 번째는 플래시론에 고정 수수료를 사용하는 것이다.
[M-02] Undercounted liquidity leads to increased volumePerLiquidityInBlock() and incorrect adaptive fee
Undercounted liquidity는 정확하지 않은 거래량 정보를 야기하고 적응형 fee 계산에 영향을 미친다. 대부분의 경우에 거래량은 과대평가된다. 그리고 수수료는 낮아진다.
TechPaper에 따르면 거래량은 적응형 스왑 fee를 계산하는데 사용되는 세 가지 지표 중 하나이다. 자산의 행동 특성에 따라 최적의 수수료 금액을 찾기 위해서는 다음 지표들이 모니터링된다. 1. 변동성 2. 유동성 3. 거래량
TechPaper에서 유동성 대비 거래량이 어떻게 계산되는지는 다음과 같다.
$I_t = \frac{\widetilde{L}\_t}{L_t}$
여기서
$\widetilde{L}\_t = \sqrt{V\_1 \* V\_2}$
는 자산1과 2의 평균 거래량이고
$L_t$
는 거래 중에 사용된 유동성이다.
유니스왑 v3에서 유동성은 이산적인 가격 범위에 집중되어 있다. 이는 유니스왑 대시보드에서 확인할 수 있다. 스왑을 하는 동안 현재 가격은 가격 범위 내에서 움직이고, 가격 범위 내에 스왑을 충족시킬 충분한 유동성이 없을 때 인접한 유동성 위치로 점프한다.
큰 스왑과 좁은 유동성 위치의 경우에 현재 가격은 스왑이 충족될 때까지 여러 중간 유동성 위치를 거치고 최종적으로 다른 가격 범위에서 멈출 수 있다. 이러한 상황에서 스왑을 충족시키기 위해 필요한 유동성은 다음으로 구성된다.
1. 초기 가격 범위 유동성 2. 중간 가격 범위의 유동성 3. 가격이 멈춘 최종 가격 범위의 유동성
TechPaper에 따르면 $L_t$ 는 스왑을 수행하기 위해 필요한 유동성이라서 초기 및 최종 가격 범위 뿐만 아니라 중간 가격 범위의 유동성도고려해야 할 것으로 예상된다. 그러나 코드에서는 최종 가격 범위의 유동성만을 계산한다. calcauldateVolumePerLiquidity()가 호출될 때, currentLiquidity는 새 가격에 사용가능한 유동성이고 이것은 새 가격을 포함하는 가격 범위만 포함한다. 스왑동안에 currentLiquidity는 여러 번 업데이트된다.
가격이 유동성 위치를 지나갈 때 새로운 유동성이 추가되거나 제거 될 때 초기 가격 범위와 모든 중간 가격 범위의 유동성은 calculateVolumePerLiquidity()에 의해서 계산되지 않는다.
스왑 수수료 역시 스왑에 차여한 유동성에 대해 계산된다. 코드에서 스왑수수료는 메인 스왑 루프 내에서 호출되고 가격이 한 가격 범위에서 다른 가격 범위로 이동하고 유동성이 추가되고 제거됨에 따라 여러 번 currentLiquidity를 받는 movePriceTowardsTarget()에 의해서 계산된다. 따라서 스왑 수수료는 항상 스왑에 필요한 전체 유동성에 대해 계산되는 반면, 거래량 계산은 스왑이 완료된 후 새 가격을 포함하는 가격 범위만을 계산한다.
그렇기 때문에 스왑에 필요한 전체 유동성에 대한 유동성 당 거래량을 계산하려면 스왑 수수료 금액 계산을 참조해서 사용할 수 있다.
'Audit Report' 카테고리의 다른 글
[Audit Report] Particle Protocol (1) | 2024.02.12 |
---|---|
[Audit Report] Lens Protocol V2 (0) | 2024.01.26 |
[Audit Report] Axelar Network (2) (1) | 2024.01.21 |
[Audit Report] Axelar Network (1) (0) | 2024.01.18 |
[Audit Report] Trader Joe v2 (2) (1) | 2024.01.14 |