Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FlatOperator can be inlined into NestedFactory to save gas #26

Open
code423n4 opened this issue Nov 13, 2021 · 2 comments
Open

FlatOperator can be inlined into NestedFactory to save gas #26

code423n4 opened this issue Nov 13, 2021 · 2 comments
Labels
bug Something isn't working G (Gas Optimization) sponsor acknowledged Technically the issue is correct, but we're not going to resolve it for XYZ reasons

Comments

@code423n4
Copy link
Contributor

Handle

TomFrench

Vulnerability details

Impact

Reduced gas costs from not having to load operator address from storage and make external contract call to FlatOperator

Proof of Concept

FlatOperator is going to be used on almost any operation as it's very likely that people will be investing into a portfolio using one of the tokens in that portfolio. Despite having all the information necessary to return the correct output NestedFactory has to load the FlatOperator address from storage and then make a contract call to the FlatOperator (touching an additional contract) incurring all the associated costs of this.

As the FlatOperator is such a simple and commonly used operator it's worth inlining it into NestedFactory._submitOrder and NestedFactory._safeSubmitOrder.

_submitOrder could then be modified as similarly to this:

function _submitOrder(
  address _inputToken,
  address _outputToken,
  uint256 _nftId,
  Order calldata _order,
  bool _reserved
) private returns (uint256 amountSpent) {
  uint256[] memory amounts = new uint256[](2);
  address[] memory tokens = new address[](2);
  
  // Exact method of specifying when to trigger this is up to you.
  if (_order.operator == "Flat"){
   // Extract amount from calldata (you could also remove the token address from calldata)
   (, uint256 amount) = abi.decode(_order, (address, uint256))
   
   amounts[0] = amount;
   amounts[1] = amount;
  } else {
    address operator = requireAndGetAddress(_order.operator);
    (bool success, bytes memory data) = OperatorHelpers.callOperator(operator, _order.commit, _order.callData);
    require(success, "NestedFactory::_submitOrder: Operator call failed");

    (amounts, tokens) = OperatorHelpers.decodeDataAndRequire(
      data,
      _inputToken,
      _outputToken
    );
  }
 

  if (_reserved) {
    _transferToReserveAndStore(_outputToken, amounts[0], _nftId);
  }
  amountSpent = amounts[1];
}

We then shortcut this function saving gas.

Recommended Mitigation Steps

Something similar to above snippet.

@code423n4 code423n4 added bug Something isn't working G (Gas Optimization) labels Nov 13, 2021
code423n4 added a commit that referenced this issue Nov 13, 2021
@maximebrugel maximebrugel self-assigned this Nov 18, 2021
@maximebrugel
Copy link
Collaborator

We prefer to keep the FlatOperator for maximum modularity and readability of NestedFactory.
However, we are aware that this is a significant optimization.

@maximebrugel maximebrugel added the sponsor acknowledged Technically the issue is correct, but we're not going to resolve it for XYZ reasons label Nov 23, 2021
@maximebrugel
Copy link
Collaborator

Maybe we'll do a POC and confirm later. But we will acknowledge for now.

@maximebrugel maximebrugel removed their assignment Nov 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working G (Gas Optimization) sponsor acknowledged Technically the issue is correct, but we're not going to resolve it for XYZ reasons
Projects
None yet
Development

No branches or pull requests

2 participants