Omniscia Tangible Audit

Exchange Code Style Findings

Exchange Code Style Findings

EEG-01C: Inefficient mapping Lookups

Description:

The linked statements perform key-based lookup operations on mapping declarations from storage multiple times for the same key redundantly.

Example:

contracts/Exchange.sol
123} else {
124 amounts = new uint256[](routePaths[tokenized].length);
125 amounts = IRouter(_router).swapExactTokensForTokens(
126 amountIn,
127 minAmountOut,
128 routePaths[tokenized],
129 msg.sender,
130 block.timestamp
131 );
132}

Recommendation:

As the lookups internally perform an expensive keccak256 operation, we advise the lookups to be cached wherever possible to a single local declaration that either holds the value of the mapping in case of primitive types or holds a storage pointer to the struct contained.

Alleviation (2ad448279d9e8e4b6edd94bcd2eb22129b6f7357):

All referenced inefficient mapping lookups have been optimized to the greatest extent possible, significantly reducing the gas cost of the functions the statements were located in.

EEG-02C: Sub-Optimal Inverse Route Management

Description:

The overall Exchange contract and specifically its Exchange::addRouterForTokens function will inefficiently maintain duplicate data entries for the trade route it wishes to support between two tokens.

Example:

contracts/Exchange.sol
56function addRouterForTokens(
57 address tokenInAddress,
58 address tokenOutAddress,
59 address _router,
60 IRouter.Route[] calldata _routes,
61 IRouter.Route[] calldata _routesReversed,
62 bool _simpleSwap,
63 bool _stable
64) external onlyFactoryOwner {
65 require(_routes.length == _routesReversed.length, "mismatch");
66 bytes memory tokenized = abi.encodePacked(tokenInAddress, tokenOutAddress);
67 bytes memory tokenizedReverse = abi.encodePacked(tokenOutAddress, tokenInAddress);
68 // set routes
69 routers[tokenized] = _router;
70 routers[tokenizedReverse] = _router;
71 // set paths if any
72 uint256 length = _routes.length;
73 for (uint256 i; i < length; ) {
74 routePaths[tokenized].push(_routes[i]);
75 routePaths[tokenizedReverse].push(_routesReversed[i]);
76 unchecked {
77 ++i;
78 }
79 }
80 // set if simple swap or with hops
81 simpleSwap[tokenized] = _simpleSwap;
82 simpleSwap[tokenizedReverse] = _simpleSwap;
83 //set if pool is stable or not
84 stable[tokenized] = _stable;
85 stable[tokenizedReverse] = _stable;
86}

Recommendation:

We advise the Exchange contract to sort the in and out tokens of a swap similarly to Uniswap and to maintain a single data entry for each.

If the inverse trade path is requested, we advise the canonical trade path to be loaded from storage and to be reversed using a local memory variable which will significantly optimize the gas cost of maintaining trade routes.

Alleviation (2ad448279d9e8e4b6edd94bcd2eb22129b6f7357):

The Exchange contract was revised to integrate with Uniswap V3 like pools, thereby no longer requiring complex router paths in reverse order.

As such, we consider this optimization no longer applicable.