Skip to content
This repository has been archived by the owner on May 26, 2023. It is now read-only.

Latest commit

 

History

History
126 lines (96 loc) · 3.54 KB

046.md

File metadata and controls

126 lines (96 loc) · 3.54 KB

ctf_sec

medium

TokenX fee can be locked in BufferRouter.sol if trade processing fail sliently.

Summary

TokenX fee can be locked in BufferRouter.sol if trade processing fail sliently.

Vulnerability Detail

When a trade is queued, We are calling:

optionsContract.runInitialChecks(slippage, period, totalFee);

// Transfer the fee specified from the user to this contract.
// User has to approve first inorder to execute this function
IERC20(optionsContract.tokenX()).transferFrom(
    msg.sender,
    address(this),
    totalFee
);

totalFee cannot be 0 because the optionsContract.runInitialChecks(slippage, period, totalFee) did the sanity check:

  /**
   * @notice Runs the basic checks for option creation
   */
  function runInitialChecks(
      uint256 slippage,
      uint256 period,
      uint256 totalFee
  ) external view override {
      require(!isPaused, "O33");
      require(slippage <= 5e2, "O34"); // 5% is the max slippage a user can use
      require(period >= config.minPeriod(), "O21");
      require(period <= config.maxPeriod(), "O25");
      require(totalFee >= config.minFee(), "O35");
  }

let us just assume that the tokenX used is USDC, has 6 decimals, and the totalFee is set to 1e6 in OptionConfig.

uint256 public override minFee = 1e6; // set

every time user queue a trade, a 1e6 amount of USDC will be transferred into the BufferRouter.sol

In normal case, when trade is canceled, this fee is refunded.

_cancelQueuedTrade(queueId);

which calls:

function _cancelQueuedTrade(uint256 queueId) internal {
	QueuedTrade storage queuedTrade = queuedTrades[queueId];
	IBufferBinaryOptions optionsContract = IBufferBinaryOptions(
		queuedTrade.targetContract
	);
	queuedTrade.isQueued = false;
	IERC20(optionsContract.tokenX()).transfer(
		queuedTrade.user,
		queuedTrade.totalFee
	);

	userCancelledQueuedIds[queuedTrade.user].push(queueId);
}

However, there is a one case that the fee will not be refunded and the fee will be locked in the BufferRouter.sol.

/**
 * @notice Verifies the trade parameter via the signature and resolves all the valid queued trades
 */
function resolveQueuedTrades(OpenTradeParams[] calldata params) external {
	_validateKeeper();
	for (uint32 index = 0; index < params.length; index++) {
		OpenTradeParams memory currentParams = params[index];
		QueuedTrade memory queuedTrade = queuedTrades[
			currentParams.queueId
		];
		bool isSignerVerifed = _validateSigner(
			currentParams.timestamp,
			currentParams.asset,
			currentParams.price,
			currentParams.signature
		);
		// Silently fail if the signature doesn't match
		if (!isSignerVerifed) {
			emit FailResolve(
				currentParams.queueId,
				"Router: Signature didn't match"
			);
			continue;
		}

if the signature is invalid, the queue trades fails sliently. There will be no refund in the fee, fee is locked in the Router contract given that the BufferRouter is not upgradeable and there is no rescueToken related function to sweep the dust token.

Impact

TokenX fee can be locked in Router contract.

Code Snippet

https://github.com/sherlock-audit/2022-11-buffer/blob/main/contracts/contracts/core/BufferRouter.sol#L354-L365

https://github.com/sherlock-audit/2022-11-buffer/blob/main/contracts/contracts/core/BufferRouter.sol#L132-L156

Tool used

Manual Review

Recommendation

We recommend the project transfer the fee out to admin address or refund the fee will the signature has issue to not let the trade processing fails sliently and get the fee locked in the contract.