Malicious users can obtain large amounts of FMP by repeatedly opening and closing position.
Vulnerability Detail
When a DelayedOrder is created, it will be written to _announcedOrder[msg.sender]. It is defined as mapping(address account => FlatcoinStructs.Order order). An Order structure is defined as follows:
File: flatcoin-v1\src\libraries\FlatcoinStructs.sol
60: struct Order {
61: OrderType orderType;
62: uint256 keeperFee; // The deposit paid upon submitting that needs to be paid / refunded on tx confirmation
63:-> uint64 executableAtTime; // The timestamp at which this order is executable at
64: bytes orderData;
65: }
When the price of the collateral is stable and does not fluctuate violently. Malicious users may need to spend a small fee to obtain FMP. In good cases, it can even be profitable. Let’s give an example to illustrate.
Bob wrote a robot to automatically open and close positions. A process is as follows:
Call announceLeverageOpen to create a pending LeverageOpen order. The margin is 1e18 collateral and the additionalSize is 3e18.
After minExecutabilityAge seconds have passed, the robot, as the keeper, calls DelayedOrder.executeOrder to execute the pending order created in step 1. Therefore, the position is opened, and the number of FMP that bob gets is: additionalSize * pointsPerSize / 1e18. Through the test from [test setup](https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/test/helpers/Setup.sol#L201), we know that pointsPerSize = 100e18. Then, the amount of FMP obtained in this case is: 3e18 * 100e18 / 1e18 = 300e18.
Call announceLeverageClose to create a pending LeverageClose order.
After minExecutabilityAge seconds have passed, the robot calls DelayedOrder.executeOrder to execute the pending order created in step 3. Therefore, the position is closed.
The life cycle of a position may be minExecutabilityAge(5) seconds. In the Base chain, a block is mined in an average of 2 seconds, which means that the life cycle of a position may be 3-4 blocks. The fundFee generated during this time period is basically negligible. If the price of collateral stabilizes, malicious users can take advantage of this issue to obtain large amounts of FMP at a small cost. If the closing price is greater than the opening price, the position can be profitable.
Therefore, it is possible to automate the above process to obtain large quantities of FMP.
Impact
FMP serves as an incentive for users as a protocol. We can think of it as a reward token. Malicious users can obtain large amounts of FMP at a small cost.
nobody2018
medium
Malicious users can obtain large amounts of FMP at a small cost
Summary
FMP is distributed to both long and short parties as an incentive.
Malicious users can obtain large amounts of FMP by repeatedly opening and closing position.
Vulnerability Detail
When a DelayedOrder is created, it will be written to
_announcedOrder[msg.sender]
. It is defined asmapping(address account => FlatcoinStructs.Order order)
. AnOrder
structure is defined as follows:Order.executableAtTime
is set toblock.timestamp + minExecutabilityAge(5s)
. This means that when a pending order is created, it must wait at least 5 seconds before being executed. Pending orders will expire, and the order execution time cannot be greater thanOrder.executableAtTime + maxExecutabilityAge (60s)
. [_prepareExecutionOrder](https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/DelayedOrder.sol#L650-L658) is used to check whetherOrder.executableAtTime
meets the conditions.When the price of the collateral is stable and does not fluctuate violently. Malicious users may need to spend a small fee to obtain FMP. In good cases, it can even be profitable. Let’s give an example to illustrate.
Bob wrote a robot to automatically open and close positions. A process is as follows:
announceLeverageOpen
to create a pending LeverageOpen order. Themargin
is 1e18 collateral and theadditionalSize
is 3e18.minExecutabilityAge
seconds have passed, the robot, as the keeper, callsDelayedOrder.executeOrder
to execute the pending order created in step 1. Therefore, the position is opened, and the number of FMP that bob gets is:additionalSize * pointsPerSize / 1e18
. Through the test from [test setup](https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/test/helpers/Setup.sol#L201), we know thatpointsPerSize = 100e18
. Then, the amount of FMP obtained in this case is:3e18 * 100e18 / 1e18 = 300e18
.announceLeverageClose
to create a pending LeverageClose order.minExecutabilityAge
seconds have passed, the robot callsDelayedOrder.executeOrder
to execute the pending order created in step 3. Therefore, the position is closed.The life cycle of a position may be
minExecutabilityAge(5)
seconds. In the Base chain, a block is mined in an average of 2 seconds, which means that the life cycle of a position may be 3-4 blocks. ThefundFee
generated during this time period is basically negligible. If the price of collateral stabilizes, malicious users can take advantage of this issue to obtain large amounts of FMP at a small cost. If the closing price is greater than the opening price, the position can be profitable.Therefore, it is possible to automate the above process to obtain large quantities of FMP.
Impact
FMP serves as an incentive for users as a protocol. We can think of it as a reward token. Malicious users can obtain large amounts of FMP at a small cost.
Code Snippet
https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/LeverageModule.sol#L133
https://github.com/sherlock-audit/2023-12-flatmoney/blob/main/flatcoin-v1/src/StableModule.sol#L84
Tool used
Manual Review
Recommendation
A mechanism is needed to prevent such behavior.
Duplicate of #187