code-423n4 / 2022-06-connext-findings

1 stars 0 forks source link

Gas Optimizations #185

Open code423n4 opened 2 years ago

code423n4 commented 2 years ago

Summary

Gas Optimizations

Issue Instances
1 Multiple address mappings can be combined into a single mapping of an address to a struct, where appropriate 1
2 State variables only set in the constructor should be declared immutable 1
3 Structs can be packed into fewer storage slots 2
4 Using calldata instead of memory for read-only arguments in external functions saves gas 10
5 Using storage instead of memory for structs/arrays saves gas 2
6 State variables should be cached in stack variables rather than re-reading them from storage 13
7 Multiple accesses of a mapping/array should use a local variable cache 13
8 internal functions only called once can be inlined to save gas 9
9 Add unchecked {} for subtractions where the operands cannot underflow because of a previous require() or if-statement 4
10 <array>.length should not be looked up in every loop of a for-loop 19
11 ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for- and while-loops 26
12 require()/revert() strings longer than 32 bytes cost extra gas 17
13 Optimize names to save gas 3
14 Using bools for storage incurs overhead 3
15 Use a more recent version of solidity 1
16 Using > 0 costs more gas than != 0 when used on a uint in a require() statement 2
17 >= costs less gas than > 2
18 It costs more gas to initialize non-constant/non-immutable variables to zero than to let the default of zero be applied 22
19 internal functions not called by the contract should be removed to save deployment gas 2
20 ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too) 26
21 Splitting require() statements that use && saves gas 6
22 Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead 142
23 Using private rather than public for constants, saves gas 6
24 Don't use SafeMath once the solidity version is 0.8.0 or greater 3
25 Duplicated require()/revert() checks should be refactored to a modifier or function 7
26 Multiple if-statements with mutually-exclusive conditions should be changed to if-else statements 1
27 require() or revert() statements that check input arguments should be at the top of the function 6
28 Empty blocks should be removed or emit something 1
29 Superfluous event fields 4
30 Use custom errors rather than revert()/require() strings to save gas 79
31 Functions guaranteed to revert when called by normal users can be marked payable 85

Total: 518 instances over 31 issues

Gas Optimizations

1. Multiple address mappings can be combined into a single mapping of an address to a struct, where appropriate

Saves a storage slot for the mapping. Depending on the circumstances and sizes of types, can avoid a Gsset (20000 gas) per mapping combined. Reads and subsequent writes can also be cheaper when a function requires both values and they both fit in the same storage slot. Finally, if both fields are accessed in the same function, can save ~42 gas per access due to not having to recalculate the key's keccak256 hash (Gkeccak256 - 30 gas) and that calculation's associated stack operations.

There is 1 instance of this issue:

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol   #1

62      mapping(address => PriceInfo) public priceRecords;
63:     mapping(address => uint256) public assetPrices;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L62-L63

2. State variables only set in the constructor should be declared immutable

Avoids a Gsset (20000 gas) in the constructor, and replaces each Gwarmacces (100 gas) with a PUSH32 (3 gas).

There is 1 instance of this issue:

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol   #1

49:     address public wrapped;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L49

3. Structs can be packed into fewer storage slots

Each slot saved can avoid an extra Gsset (20000 gas) for the first setting of the struct. Subsequent reads as well as writes have smaller gas savings

There are 2 instances of this issue:

File: contracts/contracts/core/connext/libraries/LibConnextStorage.sol   #1

/// @audit Variable ordering with 8 slots instead of the current 9:
/// @audit  bytes(32):callData, uint256(32):callbackFee, uint256(32):relayerFee, uint256(32):slippageTol, address(20):to, uint32(4):originDomain, uint32(4):destinationDomain, bool(1):forceSlow, bool(1):receiveLocal, address(20):agent, address(20):recovery, address(20):callback
38    struct CallParams {
39      address to;
40      bytes callData;
41      uint32 originDomain;
42      uint32 destinationDomain;
43      address agent;
44      address recovery;
45      address callback;
46      uint256 callbackFee;
47      uint256 relayerFee;
48      bool forceSlow;
49      bool receiveLocal;
50      uint256 slippageTol;
51:   }

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibConnextStorage.sol#L38-L51

File: contracts/contracts/core/connext/libraries/LibConnextStorage.sol   #2

/// @audit Move all of the bools next to eachother and the addresses next to eachother in order to save some storage slots
109   struct AppStorage {
110     bool initialized;
111     //
112     // ConnextHandler
113     //
114     // 0
115     uint256 LIQUIDITY_FEE_NUMERATOR;
116     // 1
117     uint256 LIQUIDITY_FEE_DENOMINATOR;
118     // The local nomad relayer fee router
119     // 2
120     RelayerFeeRouter relayerFeeRouter;
121     // The local nomad promise callback router
122     // 3
123     PromiseRouter promiseRouter;
124     // /**
125     // * @notice The address of the wrapper for the native asset on this domain
126     // * @dev Needed because the nomad only handles ERC20 assets
127     // */
128     // 4
129     IWrapped wrapper;
130     // /**
131     // * @notice Nonce for the contract, used to keep unique transfer ids.
132     // * @dev Assigned at first interaction (xcall on origin domain);
133     // */
134     // 5
135     uint256 nonce;
136     // /**
137     // * @notice The external contract that will execute crosschain calldata
138     // */
139     // 6
140     IExecutor executor;
141     // /**
142     // * @notice The domain this contract exists on
143     // * @dev Must match the nomad domain, which is distinct from the "chainId"
144     // */
145     // 7
146     uint256 domain;
147     // /**
148     // * @notice The local nomad token registry
149     // */
150     // 8
151     ITokenRegistry tokenRegistry;
152     // /**
153     // * @notice Mapping holding the AMMs for swapping in and out of local assets
154     // * @dev Swaps for an adopted asset <> nomad local asset (i.e. POS USDC <> madUSDC on polygon)
155     // */
156     // 9
157     mapping(bytes32 => IStableSwap) adoptedToLocalPools;
158     // /**
159     // * @notice Mapping of whitelisted assets on same domain as contract
160     // * @dev Mapping is keyed on the canonical token identifier matching what is stored in the token
161     // * registry
162     // */
163     // 10
164     mapping(bytes32 => bool) approvedAssets;
165     // /**
166     // * @notice Mapping of canonical to adopted assets on this domain
167     // * @dev If the adopted asset is the native asset, the keyed address will
168     // * be the wrapped asset address
169     // */
170     // 11
171     mapping(address => ConnextMessage.TokenId) adoptedToCanonical;
172     // /**
173     // * @notice Mapping of adopted to canonical on this domain
174     // * @dev If the adopted asset is the native asset, the stored address will be the
175     // * wrapped asset address
176     // */
177     // 12
178     mapping(bytes32 => address) canonicalToAdopted;
179     // /**
180     // * @notice Mapping to determine if transfer is reconciled
181     // */
182     // 13
183     mapping(bytes32 => bool) reconciledTransfers;
184     // /**
185     // * @notice Mapping holding router address that provided fast liquidity
186     // */
187     // 14
188     mapping(bytes32 => address[]) routedTransfers;
189     // /**
190     // * @notice Mapping of router to available balance of an asset
191     // * @dev Routers should always store liquidity that they can expect to receive via the bridge on
192     // * this domain (the nomad local asset)
193     // */
194     // 15
195     mapping(address => mapping(address => uint256)) routerBalances;
196     // /**
197     // * @notice Mapping of approved relayers
198     // * @dev Send relayer fee if msg.sender is approvedRelayer. otherwise revert()
199     // */
200     // 16
201     mapping(address => bool) approvedRelayers;
202     // /**
203     // * @notice Stores the relayer fee for a transfer. Updated on origin domain when a user calls xcall or bump
204     // * @dev This will track all of the relayer fees assigned to a transfer by id, including any bumps made by the relayer
205     // */
206     // 17
207     mapping(bytes32 => uint256) relayerFees;
208     // /**
209     // * @notice Stores the relayer of a transfer. Updated on the destination domain when a relayer calls execute
210     // * for transfer
211     // * @dev When relayer claims, must check that the msg.sender has forwarded transfer
212     // */
213     // 18
214     mapping(bytes32 => address) transferRelayer;
215     // /**
216     // * @notice The max amount of routers a payment can be routed through
217     // */
218     // 19
219     uint256 maxRoutersPerTransfer;
220     // /**
221     //  * @notice The Vault used for sponsoring fees
222     //  */
223     // 20
224     ISponsorVault sponsorVault;
225     //
226     // Router
227     //
228     // 21
229     mapping(uint32 => bytes32) remotes;
230     //
231     // XAppConnectionClient
232     //
233     // 22
234     XAppConnectionManager xAppConnectionManager;
235     //
236     // ProposedOwnable
237     //
238     // 23
239     address _proposed;
240     // 24
241     uint256 _proposedOwnershipTimestamp;
242     // 25
243     bool _routerOwnershipRenounced;
244     // 26
245     uint256 _routerOwnershipTimestamp;
246     // 27
247     bool _assetOwnershipRenounced;
248     // 28
249     uint256 _assetOwnershipTimestamp;
250     //
251     // RouterFacet
252     //
253     // 29
254     RouterPermissionsManagerInfo routerPermissionInfo;
255     //
256     // ReentrancyGuard
257     //
258     // 30
259     uint256 _status;
260     //
261     // StableSwap
262     //
263     /**
264      * @notice Mapping holding the AMM storages for swapping in and out of local assets
265      * @dev Swaps for an adopted asset <> nomad local asset (i.e. POS USDC <> madUSDC on polygon)
266      * Struct storing data responsible for automatic market maker functionalities. In order to
267      * access this data, this contract uses SwapUtils library. For more details, see SwapUtils.sol
268      */
269     // 31
270     mapping(bytes32 => SwapUtils.Swap) swapStorages;
271     /**
272      * @notice Maps token address to an index in the pool. Used to prevent duplicate tokens in the pool.
273      * @dev getTokenIndex function also relies on this mapping to retrieve token index.
274      */
275     // 32
276     mapping(bytes32 => mapping(address => uint8)) tokenIndexes;
277     /**
278      * @notice Stores whether or not briding, AMMs, have been paused
279      */
280     // 33
281     bool _paused;
282     //
283     // AavePortals
284     //
285     /**
286      * @notice Address of Aave Pool contract
287      */
288     address aavePool;
289     /**
290      * @notice Fee percentage numerator for using Portal liquidity
291      * @dev Assumes the same basis points as the liquidity fee
292      */
293     uint256 aavePortalFeeNumerator;
294     /**
295      * @notice Mapping to store the transfer liquidity amount provided by Aave Portals
296      */
297     mapping(bytes32 => uint256) portalDebt;
298     /**
299      * @notice Mapping to store the transfer liquidity amount provided by Aave Portals
300      */
301     mapping(bytes32 => uint256) portalFeeDebt;
302     //
303     // BridgeFacet (cont.) TODO: can we move this
304     //
305     /**
306      * @notice Stores whether a transfer has had `receiveLocal` overrides forced
307      */
308     // 34
309     mapping(bytes32 => bool) receiveLocalOverrides;
310:  }

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibConnextStorage.sol#L109-L310

4. Using calldata instead of memory for read-only arguments in external functions saves gas

When a function with a memory array is called externally, the abi.decode() step has to use a for-loop to copy each index of the calldata to the memory index. Each iteration of this for-loop costs at least 60 gas (i.e. 60 * <mem_array>.length). Using calldata directly, obliviates the need for such a loop in the contract code and runtime execution.

If the array is passed to an internal function which passes the array to another internal function where the array is modified and therefore memory is used in the external call, it's still more gass-efficient to use calldata when the external function uses modifiers, since the modifiers may prevent the internal functions from being called. Structs have the same overhead as an array of length one

There are 10 instances of this issue:

File: contracts/contracts/core/connext/facets/StableSwapFacet.sol

395:      IERC20[] memory _pooledTokens,

396:      uint8[] memory decimals,

397:      string memory lpTokenName,

398:      string memory lpTokenSymbol,

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/StableSwapFacet.sol#L395

File: contracts/contracts/core/connext/facets/BridgeFacet.sol

393:      bytes memory _message

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BridgeFacet.sol#L393

File: contracts/contracts/core/connext/helpers/Executor.sol

113:    function execute(ExecutorArgs memory _args) external payable override onlyConnext returns (bool, bytes memory) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/Executor.sol#L113

File: contracts/contracts/core/connext/helpers/LPToken.sol

21:     function initialize(string memory name, string memory symbol) external initializer returns (bool) {

21:     function initialize(string memory name, string memory symbol) external initializer returns (bool) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/LPToken.sol#L21

File: contracts/contracts/core/promise/PromiseRouter.sol

209:      bytes memory _message

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/promise/PromiseRouter.sol#L209

File: contracts/contracts/core/relayer-fee/RelayerFeeRouter.sol

134:      bytes memory _message

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/relayer-fee/RelayerFeeRouter.sol#L134

5. Using storage instead of memory for structs/arrays saves gas

When fetching data from a storage location, assigning the data to a memory variable causes all fields of the struct/array to be read from storage, which incurs a Gcoldsload (2100 gas) for each field of the struct/array. If the fields are read from the new memory variable, they incur an additional MLOAD rather than a cheap stack read. Instead of declearing the variable with the memory keyword, declaring the variable with the storage keyword and caching any fields that need to be re-read in stack variables, will be much cheaper, only incuring the Gcoldsload for the fields actually read. The only time it makes sense to read the whole struct/array into a memory variable, is if the full struct/array is being returned by the function, is being passed to a function that requires memory, or if the array/struct is being read from another memory array/struct

There are 2 instances of this issue:

File: contracts/contracts/core/connext/facets/BridgeFacet.sol   #1

591:      address[] memory routers = s.routedTransfers[transferId];

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BridgeFacet.sol#L591

File: contracts/contracts/core/connext/facets/PortalFacet.sol   #2

134:      ConnextMessage.TokenId memory canonical = s.adoptedToCanonical[adopted];

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/PortalFacet.sol#L134

6. State variables should be cached in stack variables rather than re-reading them from storage

The instances below point to the second+ access of a state variable within a function. Caching of a state variable replace each Gwarmaccess (100 gas) with a much cheaper stack read. Other less obvious fixes/optimizations include having local memory caches of state variable structs, or having local caches of state variable contracts/addresses.

There are 13 instances of this issue:

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol

/// @audit v1PriceOracle on line 93
94:         tokenPrice = IPriceOracle(v1PriceOracle).getTokenPrice(tokenAddress);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L94

File: contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol

/// @audit _proposed on line 262
265:      _setOwner(_proposed);

/// @audit _proposed on line 274
286:      _setOwner(_proposed);

/// @audit _proposed on line 322
323:      emit OwnershipProposed(_proposed);

/// @audit _proposedOwnershipTimestamp on line 255
258:      if ((block.timestamp - _proposedOwnershipTimestamp) <= _delay)

/// @audit _routerOwnershipTimestamp on line 175
178:      if ((block.timestamp - _routerOwnershipTimestamp) <= _delay)

/// @audit _routerOwnershipTimestamp on line 292
293:      emit RouterOwnershipRenunciationProposed(_routerOwnershipTimestamp);

/// @audit _assetOwnershipTimestamp on line 217
220:      if ((block.timestamp - _assetOwnershipTimestamp) <= _delay)

/// @audit _assetOwnershipTimestamp on line 303
304:      emit AssetOwnershipRenunciationProposed(_assetOwnershipTimestamp);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol#L265

File: contracts/contracts/core/connext/helpers/SponsorVault.sol

/// @audit relayerFeeCap on line 256
256:        sponsoredFee = sponsoredFee > relayerFeeCap ? relayerFeeCap : sponsoredFee;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/SponsorVault.sol#L256

File: contracts/contracts/core/shared/ProposedOwnable.sol

/// @audit _proposed on line 132
135:      _setOwner(_proposed);

/// @audit _proposed on line 171
172:      emit OwnershipProposed(_proposed);

/// @audit _proposedOwnershipTimestamp on line 125
128:      if ((block.timestamp - _proposedOwnershipTimestamp) <= _delay)

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/shared/ProposedOwnable.sol#L135

7. Multiple accesses of a mapping/array should use a local variable cache

The instances below point to the second+ access of a value inside a mapping/array, within a function. Caching a mapping's value in a local storage or calldata variable when the value is accessed multiple times, saves ~42 gas per access due to not having to recalculate the key's keccak256 hash (Gkeccak256 - 30 gas) and that calculation's associated stack operations. Caching an array's struct avoids recalculating the array offsets into memory/calldata

There are 13 instances of this issue:

File: contracts/contracts/core/connext/facets/DiamondLoupeFacet.sol

/// @audit facets_[i] on line 33
34:         facets_[i].functionSelectors = ds.facetFunctionSelectors[facetAddress_].functionSelectors;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/DiamondLoupeFacet.sol#L34

File: contracts/contracts/core/connext/helpers/SponsorVault.sol

/// @audit rates[_originDomain] on line 248
249:        den = rates[_originDomain].den;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/SponsorVault.sol#L249

File: contracts/contracts/core/connext/libraries/SwapUtils.sol

/// @audit balances[i] on line 593
595:          balances[i] = balances[i].sub(amounts[i], "Cannot withdraw more than available");

/// @audit pooledTokens[i] on line 849
850:          pooledTokens[i].safeTransferFrom(msg.sender, address(this), amounts[i]);

/// @audit pooledTokens[i] on line 850
853:          amounts[i] = pooledTokens[i].balanceOf(address(this)).sub(beforeBalance);

/// @audit newBalances[i] on line 873
875:          newBalances[i] = newBalances[i].sub(fees[i]);

/// @audit balances1[i] on line 1024
1026:         balances1[i] = balances1[i].sub(fees[i]);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/SwapUtils.sol#L595

File: contracts/contracts/core/connext/libraries/LibDiamond.sol

/// @audit _diamondCut[facetIndex] on line 105
107:          addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);

/// @audit _diamondCut[facetIndex] on line 107
107:          addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);

/// @audit _diamondCut[facetIndex] on line 107
109:          replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);

/// @audit _diamondCut[facetIndex] on line 109
109:          replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);

/// @audit _diamondCut[facetIndex] on line 109
111:          removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);

/// @audit _diamondCut[facetIndex] on line 111
111:          removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibDiamond.sol#L107

8. internal functions only called once can be inlined to save gas

Not inlining costs 20 to 40 gas because of two extra JUMP instructions and additional stack operations needed for function calls.

There are 9 instances of this issue:

File: contracts/contracts/core/connext/facets/BridgeFacet.sol

481     function _formatMessage(
482       XCallArgs calldata _args,
483       address _asset,
484       bytes32 _transferId,
485       uint256 _amount
486:    ) internal returns (bytes memory) {

541:    function _reconcile(uint32 _origin, bytes memory _message) internal {

627:    function _recoverSignature(bytes32 _signed, bytes calldata _sig) internal pure returns (address) {

885     function _executePortalTransfer(
886       bytes32 _transferId,
887       uint256 _fastTransferAmount,
888       address _local,
889       address _router
890:    ) internal returns (uint256, address) {

1075    function _calculatePortalRepayment(
1076      uint256 _localAmount,
1077      bytes32 _transferId,
1078      address _local
1079    )
1080      internal
1081      returns (
1082        uint256,
1083        uint256,
1084:       uint256

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BridgeFacet.sol#L481-L486

File: contracts/contracts/core/connext/facets/BaseConnextFacet.sol

114:    function _isRemoteRouter(uint32 _domain, bytes32 _router) internal view returns (bool) {

140:    function _isReplica(address _potentialReplica) internal view returns (bool) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BaseConnextFacet.sol#L114

File: contracts/contracts/core/promise/PromiseRouter.sol

312:    function _originAndNonce(uint32 _origin, uint32 _nonce) internal pure returns (uint64) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/promise/PromiseRouter.sol#L312

File: contracts/contracts/core/relayer-fee/RelayerFeeRouter.sol

165:    function _originAndNonce(uint32 _origin, uint32 _nonce) internal pure returns (uint64) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/relayer-fee/RelayerFeeRouter.sol#L165

9. Add unchecked {} for subtractions where the operands cannot underflow because of a previous require() or if-statement

require(a <= b); x = b - a => require(a <= b); unchecked { x = b - a }

There are 4 instances of this issue:

File: contracts/contracts/core/connext/helpers/StableSwap.sol   #1

/// @audit require() on line 90
91:         precisionMultipliers[i] = 10**uint256(SwapUtils.POOL_PRECISION_DECIMALS - decimals[i]);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/StableSwap.sol#L91

File: contracts/contracts/core/connext/facets/BridgeFacet.sol   #2

/// @audit if-condition on line 1099
1101:         portalFee = availableAmount - backUnbackedAmount;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BridgeFacet.sol#L1101

File: contracts/contracts/core/connext/facets/PortalFacet.sol   #3

/// @audit if-condition on line 146
147:        uint256 missing = total - amount;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/PortalFacet.sol#L147

File: contracts/contracts/core/connext/libraries/MathUtils.sol   #4

/// @audit if-condition on line 29
30:         return a - b;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/MathUtils.sol#L30

10. <array>.length should not be looked up in every loop of a for-loop

The overheads outlined below are PER LOOP, excluding the first loop

Caching the length changes each of these to a DUP<N> (3 gas), and gets rid of the extra DUP<N> needed to store the stack offset

There are 19 instances of this issue:

File: contracts/contracts/core/connext/facets/StableSwapFacet.sol

415:      for (uint8 i = 0; i < _pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/StableSwapFacet.sol#L415

File: contracts/contracts/core/connext/facets/RelayerFacet.sol

140:      for (uint256 i; i < _transferIds.length; ) {

164:      for (uint256 i; i < _transferIds.length; ) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/RelayerFacet.sol#L140

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol

176:      for (uint256 i = 0; i < tokenAddresses.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L176

File: contracts/contracts/core/connext/helpers/StableSwap.sol

81:       for (uint8 i = 0; i < _pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/StableSwap.sol#L81

File: contracts/contracts/core/connext/libraries/SwapUtils.sol

205:      for (uint256 i = 0; i < xp.length; i++) {

558:      for (uint256 i = 0; i < balances.length; i++) {

591:      for (uint256 i = 0; i < balances.length; i++) {

844:      for (uint256 i = 0; i < pooledTokens.length; i++) {

869:        for (uint256 i = 0; i < pooledTokens.length; i++) {

924:      for (uint256 i = 0; i < amounts.length; i++) {

1014:       for (uint256 i = 0; i < pooledTokens.length; i++) {

1019:       for (uint256 i = 0; i < pooledTokens.length; i++) {

1039:     for (uint256 i = 0; i < pooledTokens.length; i++) {

1055:     for (uint256 i = 0; i < pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/SwapUtils.sol#L205

File: contracts/contracts/core/connext/libraries/LibDiamond.sol

104:      for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {

129:      for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {

147:      for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {

162:      for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibDiamond.sol#L104

11. ++i/i++ should be unchecked{++i}/unchecked{i++} when it is not possible for them to overflow, as is the case when used in for- and while-loops

The unchecked keyword is new in solidity version 0.8.0, so this only applies to that version or higher, which these instances are. This saves 30-40 gas per loop

There are 26 instances of this issue:

File: contracts/contracts/core/connext/facets/StableSwapFacet.sol

415:      for (uint8 i = 0; i < _pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/StableSwapFacet.sol#L415

File: contracts/contracts/core/connext/facets/DiamondLoupeFacet.sol

31:       for (uint256 i; i < numFacets; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/DiamondLoupeFacet.sol#L31

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol

176:      for (uint256 i = 0; i < tokenAddresses.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L176

File: contracts/contracts/core/connext/helpers/StableSwap.sol

81:       for (uint8 i = 0; i < _pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/StableSwap.sol#L81

File: contracts/contracts/core/connext/libraries/SwapUtils.sol

205:      for (uint256 i = 0; i < xp.length; i++) {

254:      for (uint256 i = 0; i < numTokens; i++) {

268:      for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {

289:      for (uint256 i = 0; i < numTokens; i++) {

300:      for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {

302:        for (uint256 j = 0; j < numTokens; j++) {

344:      for (uint256 i = 0; i < numTokens; i++) {

405:      for (uint256 i = 0; i < numTokens; i++) {

425:      for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {

558:      for (uint256 i = 0; i < balances.length; i++) {

591:      for (uint256 i = 0; i < balances.length; i++) {

844:      for (uint256 i = 0; i < pooledTokens.length; i++) {

869:        for (uint256 i = 0; i < pooledTokens.length; i++) {

924:      for (uint256 i = 0; i < amounts.length; i++) {

1014:       for (uint256 i = 0; i < pooledTokens.length; i++) {

1019:       for (uint256 i = 0; i < pooledTokens.length; i++) {

1039:     for (uint256 i = 0; i < pooledTokens.length; i++) {

1055:     for (uint256 i = 0; i < pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/SwapUtils.sol#L205

File: contracts/contracts/core/connext/libraries/LibDiamond.sol

104:      for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {

129:      for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {

147:      for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {

162:      for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibDiamond.sol#L104

12. require()/revert() strings longer than 32 bytes cost extra gas

Each extra memory word of bytes past the original 32 incurs an MSTORE which costs 3 gas

There are 17 instances of this issue:

File: contracts/contracts/core/connext/libraries/SwapUtils.sol

697:      require(dy <= self.balances[tokenIndexTo], "Cannot get more than pool balance");

784:      require(dy <= self.balances[tokenIndexTo], "Cannot get more than pool balance");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/SwapUtils.sol#L697

File: contracts/contracts/core/connext/libraries/LibDiamond.sol

66:       require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");

113:          revert("LibDiamondCut: Incorrect FacetCutAction");

121:      require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");

123:      require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");

132:        require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");

139:      require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");

141:      require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");

150:        require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function");

158:      require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");

161:      require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");

191:      require(_facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist");

193:      require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function");

224:        require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty");

226:        require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)");

236:            revert("LibDiamondCut: _init function reverted");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibDiamond.sol#L66

13. Optimize names to save gas

public/external function names and public member variable names can be optimized to save gas. See this link for an example of how it works. Below are the interfaces/abstract contracts that can be optimized so that the most frequently-called functions use the least amount of gas possible during method lookup. Method IDs that have two leading zero bytes can save 128 gas each during deployment, and renaming functions to have lower method IDs will save 22 gas per call, per sorted position shifted

There are 3 instances of this issue:

File: contracts/contracts/core/connext/helpers/PriceOracle.sol   #1

/// @audit getTokenPrice()
4:    abstract contract PriceOracle {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/PriceOracle.sol#L4

File: contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol   #2

/// @audit proposed(), proposedTimestamp(), routerOwnershipTimestamp(), assetOwnershipTimestamp(), delay(), isRouterOwnershipRenounced(), proposeRouterOwnershipRenunciation(), renounceRouterOwnership(), isAssetOwnershipRenounced(), proposeAssetOwnershipRenunciation(), renounceAssetOwnership(), renounced(), proposeNewOwner(), acceptProposedOwner()
26:   abstract contract ProposedOwnableUpgradeable is Initializable {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol#L26

File: contracts/contracts/core/shared/ProposedOwnable.sol   #3

/// @audit proposed(), proposedTimestamp(), delay(), renounced(), proposeNewOwner(), acceptProposedOwner()
28:   abstract contract ProposedOwnable is IProposedOwnable {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/shared/ProposedOwnable.sol#L28

14. Using bools for storage incurs overhead

    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/58f635312aa21f947cae5f8578638a85aa2519f5/contracts/security/ReentrancyGuard.sol#L23-L27 Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas) for the extra SLOAD, and to avoid Gsset (20000 gas) when changing from 'false' to 'true', after having been 'true' in the past

There are 3 instances of this issue:

File: contracts/contracts/core/connext/helpers/PriceOracle.sol   #1

6:      bool public constant isPriceOracle = true;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/PriceOracle.sol#L6

File: contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol   #2

54:     bool private _routerOwnershipRenounced;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol#L54

File: contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol   #3

57:     bool private _assetOwnershipRenounced;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol#L57

15. Use a more recent version of solidity

Use a solidity version of at least 0.8.2 to get simple compiler automatic inlining Use a solidity version of at least 0.8.3 to get better struct packing and cheaper multiple storage reads Use a solidity version of at least 0.8.4 to get custom errors, which are cheaper at deployment than revert()/require() strings Use a solidity version of at least 0.8.10 to have external calls skip contract existence checks if the external call has a return value

There is 1 instance of this issue:

File: contracts/contracts/core/connext/facets/upgrade-initializers/DiamondInit.sol   #1

2:    pragma solidity ^0.8.0;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/upgrade-initializers/DiamondInit.sol#L2

16. Using > 0 costs more gas than != 0 when used on a uint in a require() statement

This change saves 6 gas per instance. The optimization works until solidity version 0.8.13 where there is a regression in gas costs.

There are 2 instances of this issue:

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol   #1

150:      require(baseTokenPrice > 0, "invalid base token");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L150

File: contracts/contracts/core/connext/libraries/LibDiamond.sol   #2

247:      require(contractSize > 0, _errorMessage);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibDiamond.sol#L247

17. >= costs less gas than >

The compiler uses opcodes GT and ISZERO for solidity code that uses >, but only requires LT for >=, which saves 3 gas

There are 2 instances of this issue:

File: contracts/contracts/core/connext/helpers/SponsorVault.sol   #1

256:        sponsoredFee = sponsoredFee > relayerFeeCap ? relayerFeeCap : sponsoredFee;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/SponsorVault.sol#L256

File: contracts/contracts/core/connext/helpers/SponsorVault.sol   #2

258:        sponsoredFee = sponsoredFee > address(this).balance ? address(this).balance : sponsoredFee;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/SponsorVault.sol#L258

18. It costs more gas to initialize non-constant/non-immutable variables to zero than to let the default of zero be applied

Not overwriting the default for stack variables saves 8 gas. Storage and memory variables have larger savings

There are 22 instances of this issue:

File: contracts/contracts/core/connext/facets/StableSwapFacet.sol

415:      for (uint8 i = 0; i < _pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/StableSwapFacet.sol#L415

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol

176:      for (uint256 i = 0; i < tokenAddresses.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L176

File: contracts/contracts/core/connext/helpers/StableSwap.sol

81:       for (uint8 i = 0; i < _pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/StableSwap.sol#L81

File: contracts/contracts/core/connext/libraries/SwapUtils.sol

205:      for (uint256 i = 0; i < xp.length; i++) {

254:      for (uint256 i = 0; i < numTokens; i++) {

268:      for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {

289:      for (uint256 i = 0; i < numTokens; i++) {

300:      for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {

302:        for (uint256 j = 0; j < numTokens; j++) {

344:      for (uint256 i = 0; i < numTokens; i++) {

405:      for (uint256 i = 0; i < numTokens; i++) {

425:      for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {

558:      for (uint256 i = 0; i < balances.length; i++) {

591:      for (uint256 i = 0; i < balances.length; i++) {

844:      for (uint256 i = 0; i < pooledTokens.length; i++) {

869:        for (uint256 i = 0; i < pooledTokens.length; i++) {

924:      for (uint256 i = 0; i < amounts.length; i++) {

1014:       for (uint256 i = 0; i < pooledTokens.length; i++) {

1019:       for (uint256 i = 0; i < pooledTokens.length; i++) {

1039:     for (uint256 i = 0; i < pooledTokens.length; i++) {

1055:     for (uint256 i = 0; i < pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/SwapUtils.sol#L205

File: contracts/contracts/core/relayer-fee/libraries/RelayerFeeMessage.sol

81:       for (uint256 i = 0; i < length; ) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/relayer-fee/libraries/RelayerFeeMessage.sol#L81

19. internal functions not called by the contract should be removed to save deployment gas

If the functions are required by an interface, the contract should inherit from that interface and use the override keyword

There are 2 instances of this issue:

File: contracts/contracts/core/connext/facets/BridgeFacet.sol   #1

917     function _reconcileProcessMessage(bytes memory _message)
918       internal
919       returns (
920         uint256,
921         address,
922:        bytes32

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BridgeFacet.sol#L917-L922

File: contracts/contracts/core/connext/facets/BaseConnextFacet.sol   #2

132:    function _home() internal view returns (Home) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BaseConnextFacet.sol#L132

20. ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too)

Saves 6 gas per loop

There are 26 instances of this issue:

File: contracts/contracts/core/connext/facets/StableSwapFacet.sol

415:      for (uint8 i = 0; i < _pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/StableSwapFacet.sol#L415

File: contracts/contracts/core/connext/facets/DiamondLoupeFacet.sol

31:       for (uint256 i; i < numFacets; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/DiamondLoupeFacet.sol#L31

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol

176:      for (uint256 i = 0; i < tokenAddresses.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L176

File: contracts/contracts/core/connext/helpers/StableSwap.sol

81:       for (uint8 i = 0; i < _pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/StableSwap.sol#L81

File: contracts/contracts/core/connext/libraries/SwapUtils.sol

205:      for (uint256 i = 0; i < xp.length; i++) {

254:      for (uint256 i = 0; i < numTokens; i++) {

268:      for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {

289:      for (uint256 i = 0; i < numTokens; i++) {

300:      for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {

302:        for (uint256 j = 0; j < numTokens; j++) {

344:      for (uint256 i = 0; i < numTokens; i++) {

405:      for (uint256 i = 0; i < numTokens; i++) {

425:      for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) {

558:      for (uint256 i = 0; i < balances.length; i++) {

591:      for (uint256 i = 0; i < balances.length; i++) {

844:      for (uint256 i = 0; i < pooledTokens.length; i++) {

869:        for (uint256 i = 0; i < pooledTokens.length; i++) {

924:      for (uint256 i = 0; i < amounts.length; i++) {

1014:       for (uint256 i = 0; i < pooledTokens.length; i++) {

1019:       for (uint256 i = 0; i < pooledTokens.length; i++) {

1039:     for (uint256 i = 0; i < pooledTokens.length; i++) {

1055:     for (uint256 i = 0; i < pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/SwapUtils.sol#L205

File: contracts/contracts/core/connext/libraries/LibDiamond.sol

104:      for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {

129:      for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {

147:      for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {

162:      for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibDiamond.sol#L104

21. Splitting require() statements that use && saves gas

See this issue which describes the fact that there is a larger deployment gas cost, but with enough runtime calls, the change ends up being cheaper

There are 6 instances of this issue:

File: contracts/contracts/core/connext/helpers/StableSwap.sol

84            require(
85              tokenIndexes[address(_pooledTokens[i])] == 0 && _pooledTokens[0] != _pooledTokens[i],
86              "Duplicate tokens"
87:           );

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/StableSwap.sol#L84-L87

File: contracts/contracts/core/connext/libraries/AmplificationUtils.sol

86:       require(futureA_ > 0 && futureA_ < MAX_A, "futureA_ must be > 0 and < MAX_A");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/AmplificationUtils.sol#L86

File: contracts/contracts/core/connext/libraries/SwapUtils.sol

397:      require(tokenIndexFrom < numTokens && tokenIndexTo < numTokens, "Tokens must be in pool");

493:      require(tokenIndexFrom < xp.length && tokenIndexTo < xp.length, "Token index out of range");

524:      require(tokenIndexFrom < xp.length && tokenIndexTo < xp.length, "Token index out of range");

1007:     require(maxBurnAmount <= v.lpToken.balanceOf(msg.sender) && maxBurnAmount != 0, ">LP.balanceOf");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/SwapUtils.sol#L397

22. Usage of uints/ints smaller than 32 bytes (256 bits) incurs overhead

When using elements that are smaller than 32 bytes, your contract’s gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller than that, the EVM must use more operations in order to reduce the size of the element from 32 bytes to the desired size.

https://docs.soliditylang.org/en/v0.8.11/internals/layout_in_storage.html Use a larger size then downcast where needed

There are 142 instances of this issue:

File: contracts/contracts/core/connext/facets/StableSwapFacet.sol

107:    function getSwapToken(bytes32 canonicalId, uint8 index) public view returns (IERC20) {

119:    function getSwapTokenIndex(bytes32 canonicalId, address tokenAddress) public view returns (uint8) {

120:      uint8 index = s.tokenIndexes[canonicalId][tokenAddress];

131:    function getSwapTokenBalance(bytes32 canonicalId, uint8 index) external view returns (uint256) {

157:      uint8 tokenIndexFrom,

158:      uint8 tokenIndexTo,

211:      uint8 tokenIndex

239:      uint8 tokenIndexFrom,

240:      uint8 tokenIndexTo,

347:      uint8 tokenIndex,

415:      for (uint8 i = 0; i < _pooledTokens.length; i++) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/StableSwapFacet.sol#L107

File: contracts/contracts/core/connext/facets/VersionFacet.sol

16:     uint8 internal immutable _version = 0;

20:     function VERSION() public pure returns (uint8) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/VersionFacet.sol#L16

File: contracts/contracts/core/connext/facets/BridgeFacet.sol

68:     uint16 public constant AAVE_REFERRAL_CODE = 0;

95:       uint32 indexed origin,

142:      uint32 canonicalDomain,

327:          (uint32 canonicalDomain, bytes32 canonicalId) = s.tokenRegistry.getTokenId(transactingAssetId);

390:      uint32 _origin,

391:      uint32 _nonce,

459:      uint32 _canonicalDomain,

518:      (uint32 canonicalDomain, bytes32 canonicalId) = s.tokenRegistry.getTokenId(_asset);

541:    function _reconcile(uint32 _origin, bytes memory _message) internal {

720:      (uint32 tokenDomain, bytes32 tokenId) = s.tokenRegistry.getTokenId(_args.local);

733:      uint32 _canonicalDomain,

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BridgeFacet.sol#L68

File: contracts/contracts/core/connext/facets/AssetFacet.sol

44:     event StableSwapAdded(bytes32 canonicalId, uint32 domain, address swapPool, address caller);

55:     event AssetAdded(bytes32 canonicalId, uint32 domain, address adoptedAsset, address supportedAsset, address caller);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/AssetFacet.sol#L44

File: contracts/contracts/core/connext/facets/RelayerFacet.sol

48:     event InitiatedClaim(uint32 indexed domain, address indexed recipient, address caller, bytes32[] transferIds);

131:      uint32 _domain,

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/RelayerFacet.sol#L48

File: contracts/contracts/core/connext/facets/NomadFacet.sol

15:     function remotes(uint32 _domain) public view returns (bytes32) {

34:     function enrollRemoteRouter(uint32 _domain, bytes32 _router) external onlyOwner {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/NomadFacet.sol#L15

File: contracts/contracts/core/connext/facets/BaseConnextFacet.sol

55:     modifier onlyRemoteRouter(uint32 _origin, bytes32 _router) {

114:    function _isRemoteRouter(uint32 _domain, bytes32 _router) internal view returns (bool) {

123:    function _mustHaveRemote(uint32 _domain) internal view returns (bytes32 _remote) {

148:    function _localDomain() internal view virtual returns (uint32) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BaseConnextFacet.sol#L55

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol

12:     function decimals() external view returns (uint8);

21:     function getRoundData(uint80 _roundId)

25:         uint80 roundId,

29:         uint80 answeredInRound

36:         uint80 roundId,

40:         uint80 answeredInRound

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L12

File: contracts/contracts/core/connext/helpers/Executor.sol

43:     uint16 public MAX_COPY = 256;

88:     function origin() external view override returns (uint32) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/Executor.sol#L43

File: contracts/contracts/core/connext/helpers/StableSwap.sol

81:       for (uint8 i = 0; i < _pooledTokens.length; i++) {

154:    function getToken(uint8 index) public view override returns (IERC20) {

165:    function getTokenIndex(address tokenAddress) public view override returns (uint8) {

166:      uint8 index = tokenIndexes[tokenAddress];

176:    function getTokenBalance(uint8 index) external view override returns (uint256) {

201:      uint8 tokenIndexFrom = getTokenIndex(assetIn);

202:      uint8 tokenIndexTo = getTokenIndex(assetOut);

215:      uint8 tokenIndexFrom,

216:      uint8 tokenIndexTo,

234:      uint8 tokenIndexFrom = getTokenIndex(assetIn);

235:      uint8 tokenIndexTo = getTokenIndex(assetOut);

247:      uint8 tokenIndexFrom,

248:      uint8 tokenIndexTo,

291:    function calculateRemoveLiquidityOneToken(uint256 tokenAmount, uint8 tokenIndex)

320:      uint8 tokenIndexFrom,

321:      uint8 tokenIndexTo,

342:      uint8 tokenIndexFrom = getTokenIndex(assetIn);

343:      uint8 tokenIndexTo = getTokenIndex(assetOut);

360:      uint8 tokenIndexFrom = getTokenIndex(assetIn);

361:      uint8 tokenIndexTo = getTokenIndex(assetOut);

410:      uint8 tokenIndex,

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/StableSwap.sol#L81

File: contracts/contracts/core/connext/helpers/SponsorVault.sol

78:     event RateUpdated(uint32 originDomain, Rate oldRate, Rate newRate, address caller);

147:    function setRate(uint32 _originDomain, Rate calldata _rate) external onlyOwner {

235:      uint32 _originDomain,

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/SponsorVault.sol#L78

File: contracts/contracts/core/connext/libraries/AssetLogic.sol

45:     function getTokenIndexFromStableSwapPool(bytes32 canonicalId, address tokenAddress) internal view returns (uint8) {

47:       uint8 index = s.tokenIndexes[canonicalId][tokenAddress];

328:        uint8 tokenIndexIn = getTokenIndexFromStableSwapPool(_canonicalId, _assetIn);

329:        uint8 tokenIndexOut = getTokenIndexFromStableSwapPool(_canonicalId, _assetOut);

384:        uint8 tokenIndexIn = getTokenIndexFromStableSwapPool(id, _asset);

385:        uint8 tokenIndexOut = getTokenIndexFromStableSwapPool(id, adopted);

407:      (uint32 domain, bytes32 id) = s.tokenRegistry.getTokenId(_asset);

418:        uint8 tokenIndexIn = getTokenIndexFromStableSwapPool(id, _asset);

419:        uint8 tokenIndexOut = getTokenIndexFromStableSwapPool(id, local);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/AssetLogic.sol#L45

File: contracts/contracts/core/connext/libraries/LibConnextStorage.sol

41:     uint32 originDomain;

42:     uint32 destinationDomain;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibConnextStorage.sol#L41

File: contracts/contracts/core/connext/libraries/SwapUtils.sol

25:     event TokenSwap(address indexed buyer, uint256 tokensSold, uint256 tokensBought, uint128 soldId, uint128 boughtId);

25:     event TokenSwap(address indexed buyer, uint256 tokensSold, uint256 tokensBought, uint128 soldId, uint128 boughtId);

100:    uint8 internal constant POOL_PRECISION_DECIMALS = 18;

135:      uint8 tokenIndex

149:      uint8 tokenIndex,

175:      uint8 tokenIndex,

243:      uint8 tokenIndex,

390:      uint8 tokenIndexFrom,

391:      uint8 tokenIndexTo,

446:      uint8 tokenIndexFrom,

447:      uint8 tokenIndexTo,

463:      uint8 tokenIndexFrom,

464:      uint8 tokenIndexTo,

486:      uint8 tokenIndexFrom,

487:      uint8 tokenIndexTo,

517:      uint8 tokenIndexFrom,

518:      uint8 tokenIndexTo,

642:      uint8 tokenIndexFrom,

643:      uint8 tokenIndexTo,

692:      uint8 tokenIndexFrom,

693:      uint8 tokenIndexTo,

744:      uint8 tokenIndexFrom,

745:      uint8 tokenIndexTo,

779:      uint8 tokenIndexFrom,

780:      uint8 tokenIndexTo,

948:      uint8 tokenIndex,

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/SwapUtils.sol#L25

File: contracts/contracts/core/connext/libraries/LibDiamond.sol

20:       uint96 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array

124:      uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);

142:      uint96 selectorPosition = uint96(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);

178:      uint96 _selectorPosition,

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibDiamond.sol#L20

File: contracts/contracts/core/connext/libraries/ConnextMessage.sol

30:       uint32 domain;

156:    function formatTokenId(uint32 _domain, bytes32 _id) internal pure returns (bytes29) {

176:      uint8 _decimals

220:      uint40 _type = uint40(msgType(_message));

231:    function domain(bytes29 _tokenId) internal pure typeAssert(_tokenId, Types.TokenId) returns (uint32) {

262:    function msgType(bytes29 _message) internal pure returns (uint8) {

271:    function actionType(bytes29 _action) internal pure returns (uint8) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/ConnextMessage.sol#L30

File: contracts/contracts/core/connext/libraries/LibCrossDomainProperty.sol

29:       uint32 domain;

88:     function propertyType(bytes29 _property) internal pure returns (uint8) {

128:    function domain(bytes29 _property) internal pure typeAssert(_property, Types.DomainAndSender) returns (uint32) {

139:    function formatDomainAndSender(uint32 _domain, address _sender) internal pure returns (bytes29) {

149:    function formatDomainAndSenderBytes(uint32 _domain, address _sender) internal pure returns (bytes memory) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibCrossDomainProperty.sol#L29

File: contracts/contracts/core/promise/PromiseRouter.sol

79:       uint32 domain,

100:      uint64 indexed originAndNonce,

101:      uint32 indexed origin,

171:      uint32 _domain,

206:      uint32 _origin,

207:      uint32 _nonce,

300:    function _localDomain() internal view override(XAppConnectionClient) returns (uint32) {

312:    function _originAndNonce(uint32 _origin, uint32 _nonce) internal pure returns (uint64) {

312:    function _originAndNonce(uint32 _origin, uint32 _nonce) internal pure returns (uint64) {

312:    function _originAndNonce(uint32 _origin, uint32 _nonce) internal pure returns (uint64) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/promise/PromiseRouter.sol#L79

File: contracts/contracts/core/promise/libraries/PromiseMessage.sol

28:     uint8 private constant LENGTH_RETURNDATA_LEN = 32;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/promise/libraries/PromiseMessage.sol#L28

File: contracts/contracts/core/relayer-fee/libraries/RelayerFeeMessage.sol

29:     uint8 private constant LENGTH_ID_LEN = 32;

34:     uint8 private constant TRANSFER_ID_LEN = 32;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/relayer-fee/libraries/RelayerFeeMessage.sol#L29

File: contracts/contracts/core/relayer-fee/RelayerFeeRouter.sol

50:     event Send(uint32 domain, address recipient, bytes32[] transferIds, bytes32 remote, bytes message);

60:     event Receive(uint64 indexed originAndNonce, uint32 indexed origin, address indexed recipient, bytes32[] transferIds);

60:     event Receive(uint64 indexed originAndNonce, uint32 indexed origin, address indexed recipient, bytes32[] transferIds);

103:      uint32 _domain,

131:      uint32 _origin,

132:      uint32 _nonce,

153:    function _localDomain() internal view override(XAppConnectionClient) returns (uint32) {

165:    function _originAndNonce(uint32 _origin, uint32 _nonce) internal pure returns (uint64) {

165:    function _originAndNonce(uint32 _origin, uint32 _nonce) internal pure returns (uint64) {

165:    function _originAndNonce(uint32 _origin, uint32 _nonce) internal pure returns (uint64) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/relayer-fee/RelayerFeeRouter.sol#L50

23. Using private rather than public for constants, saves gas

If needed, the value can be read from the verified contract source code. Saves 3406-3606 gas in deployment gas due to the compiler not having to create non-payable getter functions for deployment calldata, not having to store the bytes of the value outside of where it's used, and not adding another entry to the method ID table

There are 6 instances of this issue:

File: contracts/contracts/core/connext/facets/BridgeFacet.sol

68:     uint16 public constant AAVE_REFERRAL_CODE = 0;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BridgeFacet.sol#L68

File: contracts/contracts/core/connext/helpers/PriceOracle.sol

6:      bool public constant isPriceOracle = true;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/PriceOracle.sol#L6

File: contracts/contracts/core/connext/libraries/AmplificationUtils.sol

21:     uint256 public constant A_PRECISION = 100;

22:     uint256 public constant MAX_A = 10**6;

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/AmplificationUtils.sol#L21

File: contracts/contracts/core/connext/libraries/LibCrossDomainProperty.sol

37:     bytes29 public constant EMPTY = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";

38:     bytes public constant EMPTY_BYTES = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibCrossDomainProperty.sol#L37

24. Don't use SafeMath once the solidity version is 0.8.0 or greater

Version 0.8.0 introduces internal overflow checks, so using SafeMath is redundant and adds overhead

There are 3 instances of this issue:

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol   #1

4:    import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol";

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L4

File: contracts/contracts/core/connext/libraries/AmplificationUtils.sol   #2

5:    import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol";

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/AmplificationUtils.sol#L5

File: contracts/contracts/core/connext/libraries/SwapUtils.sol   #3

4:    import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol";

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/SwapUtils.sol#L4

25. Duplicated require()/revert() checks should be refactored to a modifier or function

Saves deployment costs

There are 7 instances of this issue:

File: contracts/contracts/core/connext/libraries/SwapUtils.sol

432:      revert("Approximation did not converge");

524:      require(tokenIndexFrom < xp.length && tokenIndexTo < xp.length, "Token index out of range");

717:        require(dx <= tokenFrom.balanceOf(msg.sender), "Cannot swap more than you own");

756:      require(dy >= minDy, "Swap didn't result in min tokens");

784:      require(dy <= self.balances[tokenIndexTo], "Cannot get more than pool balance");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/SwapUtils.sol#L432

File: contracts/contracts/core/connext/libraries/LibDiamond.sol

139:      require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");

141:      require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibDiamond.sol#L139

26. Multiple if-statements with mutually-exclusive conditions should be changed to if-else statements

If two conditions are the same, their blocks should be combined

There is 1 instance of this issue:

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol   #1

87        if (tokenPrice == 0) {
88          tokenPrice = getPriceFromOracle(tokenAddress);
89        }
90        if (tokenPrice == 0) {
91          tokenPrice = getPriceFromDex(tokenAddress);
92:       }

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L87-L92

27. require() or revert() statements that check input arguments should be at the top of the function

Checks that involve constants should come before checks that involve state variables

There are 6 instances of this issue:

File: contracts/contracts/core/connext/helpers/LPToken.sol

50:       require(to != address(this), "LPToken: cannot send to itself");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/LPToken.sol#L50

File: contracts/contracts/core/connext/helpers/StableSwap.sol

167:      require(address(getToken(index)) == tokenAddress, "Token does not exist");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/StableSwap.sol#L167

File: contracts/contracts/core/connext/libraries/SwapUtils.sol

396:      require(tokenIndexFrom != tokenIndexTo, "Can't compare token to itself");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/SwapUtils.sol#L396

File: contracts/contracts/core/connext/libraries/LibDiamond.sol

123:      require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");

141:      require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");

161:      require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibDiamond.sol#L123

28. Empty blocks should be removed or emit something

The code should be refactored such that they no longer exist, or the block should do something useful, such as emitting an event or reverting. If the contract is meant to be extended, the contract should be abstract and the function signatures be added without any default implementation. If the block is an empty if-statement block to avoid doing subsequent checks in the else-if/else conditions, the else-if/else conditions should be nested under the negation of the if-statement, because they involve different classes of checks, which may lead to the introduction of errors when the code is later modified (if(x){}else if(y){...}else{...} => if(!x){if(y){...}else{...}})

There is 1 instance of this issue:

File: contracts/contracts/core/promise/PromiseRouter.sol   #1

132:    receive() external payable {}

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/promise/PromiseRouter.sol#L132

29. Superfluous event fields

block.timestamp and block.number are added to event information by default so adding them manually wastes gas

There are 4 instances of this issue:

File: contracts/contracts/core/connext/facets/ProposedOwnableFacet.sol   #1

52:     event RouterOwnershipRenunciationProposed(uint256 timestamp);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/ProposedOwnableFacet.sol#L52

File: contracts/contracts/core/connext/facets/ProposedOwnableFacet.sol   #2

56:     event AssetOwnershipRenunciationProposed(uint256 timestamp);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/ProposedOwnableFacet.sol#L56

File: contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol   #3

62:     event RouterOwnershipRenunciationProposed(uint256 timestamp);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol#L62

File: contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol   #4

66:     event AssetOwnershipRenunciationProposed(uint256 timestamp);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol#L66

30. Use custom errors rather than revert()/require() strings to save gas

Custom errors are available from solidity version 0.8.4. Custom errors save ~50 gas each time they're hitby avoiding having to allocate and store the revert string. Not defining the strings also save deployment gas

There are 79 instances of this issue:

File: contracts/contracts/core/connext/facets/BaseConnextFacet.sol

38:       require(s._status != _ENTERED, "ReentrancyGuard: reentrant call");

125:      require(_remote != bytes32(0), "!remote");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BaseConnextFacet.sol#L38

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol

72:       require(msg.sender == admin, "caller is not the admin");

150:      require(baseTokenPrice > 0, "invalid base token");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L72

File: contracts/contracts/core/connext/helpers/Executor.sol

57:       require(msg.sender == connext, "#OC:027");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/Executor.sol#L57

File: contracts/contracts/core/connext/helpers/LPToken.sol

35:       require(amount != 0, "LPToken: cannot mint 0");

50:       require(to != address(this), "LPToken: cannot send to itself");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/LPToken.sol#L35

File: contracts/contracts/core/connext/helpers/StableSwap.sol

75:       require(_pooledTokens.length > 1, "_pooledTokens.length <= 1");

76:       require(_pooledTokens.length <= 32, "_pooledTokens.length > 32");

77:       require(_pooledTokens.length == decimals.length, "_pooledTokens decimals mismatch");

84            require(
85              tokenIndexes[address(_pooledTokens[i])] == 0 && _pooledTokens[0] != _pooledTokens[i],
86              "Duplicate tokens"
87:           );

89:         require(address(_pooledTokens[i]) != address(0), "The 0 address isn't an ERC-20");

90:         require(decimals[i] <= SwapUtils.POOL_PRECISION_DECIMALS, "Token decimals exceeds max");

96:       require(_a < AmplificationUtils.MAX_A, "_a exceeds maximum");

97:       require(_fee < SwapUtils.MAX_SWAP_FEE, "_fee exceeds maximum");

98:       require(_adminFee < SwapUtils.MAX_ADMIN_FEE, "_adminFee exceeds maximum");

102:      require(lpToken.initialize(lpTokenName, lpTokenSymbol), "could not init lpToken clone");

125:      require(block.timestamp <= deadline, "Deadline not met");

155:      require(index < swapStorage.pooledTokens.length, "Out of range");

167:      require(address(getToken(index)) == tokenAddress, "Token does not exist");

177:      require(index < swapStorage.pooledTokens.length, "Index out of range");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/StableSwap.sol#L75

File: contracts/contracts/core/connext/libraries/AmplificationUtils.sol

84:       require(block.timestamp >= self.initialATime.add(1 days), "Wait 1 day before starting ramp");

85:       require(futureTime_ >= block.timestamp.add(MIN_RAMP_TIME), "Insufficient ramp time");

86:       require(futureA_ > 0 && futureA_ < MAX_A, "futureA_ must be > 0 and < MAX_A");

92:         require(futureAPrecise.mul(MAX_A_CHANGE) >= initialAPrecise, "futureA_ is too small");

94:         require(futureAPrecise <= initialAPrecise.mul(MAX_A_CHANGE), "futureA_ is too large");

111:      require(self.futureATime > block.timestamp, "Ramp is already stopped");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/AmplificationUtils.sol#L84

File: contracts/contracts/core/connext/libraries/SwapUtils.sol

191:      require(tokenIndex < xp.length, "Token index out of range");

198:      require(tokenAmount <= xp[tokenIndex], "Withdraw exceeds available");

248:      require(tokenIndex < numTokens, "Token not found");

342:      require(numTokens == precisionMultipliers.length, "Balances must match multipliers");

396:      require(tokenIndexFrom != tokenIndexTo, "Can't compare token to itself");

397:      require(tokenIndexFrom < numTokens && tokenIndexTo < numTokens, "Tokens must be in pool");

493:      require(tokenIndexFrom < xp.length && tokenIndexTo < xp.length, "Token index out of range");

524:      require(tokenIndexFrom < xp.length && tokenIndexTo < xp.length, "Token index out of range");

554:      require(amount <= totalSupply, "Cannot exceed total supply");

615:      require(index < self.pooledTokens.length, "Token index out of range");

649:        require(dx <= tokenFrom.balanceOf(msg.sender), "Cannot swap more than you own");

662:      require(dy >= minDy, "Swap didn't result in min tokens");

697:      require(dy <= self.balances[tokenIndexTo], "Cannot get more than pool balance");

703:      require(dx <= maxDx, "Swap needs more than max tokens");

717:        require(dx <= tokenFrom.balanceOf(msg.sender), "Cannot swap more than you own");

723:        require(dx == tokenFrom.balanceOf(address(this)).sub(beforeBalance), "not support fee token");

750:      require(dx <= tokenFrom.balanceOf(msg.sender), "Cannot swap more than you own");

756:      require(dy >= minDy, "Swap didn't result in min tokens");

784:      require(dy <= self.balances[tokenIndexTo], "Cannot get more than pool balance");

790:      require(dx <= maxDx, "Swap didn't result in min tokens");

823:      require(amounts.length == pooledTokens.length, "Amounts must match pooled tokens");

845:        require(v.totalSupply != 0 || amounts[i] > 0, "Must supply all tokens in pool");

861:      require(v.d1 > v.d0, "D should increase");

890:      require(toMint >= minToMint, "Couldn't mint min requested");

916:      require(amount <= lpToken.balanceOf(msg.sender), ">LP.balanceOf");

917:      require(minAmounts.length == pooledTokens.length, "minAmounts must match poolTokens");

925:        require(amounts[i] >= minAmounts[i], "amounts[i] < minAmounts[i]");

954:      require(tokenAmount <= lpToken.balanceOf(msg.sender), ">LP.balanceOf");

955:      require(tokenIndex < pooledTokens.length, "Token not found");

961:      require(dy >= minAmount, "dy < minAmount");

1005:     require(amounts.length == pooledTokens.length, "Amounts should match pool tokens");

1007:     require(maxBurnAmount <= v.lpToken.balanceOf(msg.sender) && maxBurnAmount != 0, ">LP.balanceOf");

1032:     require(tokenAmount != 0, "Burnt amount cannot be zero");

1035:     require(tokenAmount <= maxBurnAmount, "tokenAmount > maxBurnAmount");

1071:     require(newAdminFee <= MAX_ADMIN_FEE, "Fee is too high");

1084:     require(newSwapFee <= MAX_SWAP_FEE, "Fee is too high");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/SwapUtils.sol#L191

File: contracts/contracts/core/connext/libraries/LibDiamond.sol

66:       require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");

100       require(
101         diamondStorage().acceptanceTimes[keccak256(abi.encode(_diamondCut))] < block.timestamp,
102         "LibDiamond: delay not elapsed"
103:      );

121:      require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");

123:      require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");

132:        require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");

139:      require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");

141:      require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");

150:        require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function");

158:      require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");

161:      require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");

191:      require(_facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist");

193:      require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function");

224:        require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty");

226:        require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)");

247:      require(contractSize > 0, _errorMessage);

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/LibDiamond.sol#L66

File: contracts/contracts/core/connext/libraries/ConnextMessage.sol

116:      require(isValidAction(_action), "!action");

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/libraries/ConnextMessage.sol#L116

31. Functions guaranteed to revert when called by normal users can be marked payable

If a function modifier such as onlyOwner is used, the function will revert if a normal user tries to pay the function. Marking the function as payable will lower the gas cost for legitimate callers because the compiler will not include checks for whether a payment was provided. The extra opcodes avoided are CALLVALUE(2),DUP1(3),ISZERO(3),PUSH2(3),JUMPI(10),PUSH1(3),DUP1(3),REVERT(0),JUMPDEST(1),POP(2), which costs an average of about 21 gas per call to the function, in addition to the extra deployment cost

There are 85 instances of this issue:

File: contracts/contracts/core/connext/facets/StableSwapFacet.sol

393     function initializeSwap(
394       bytes32 _canonicalId,
395       IERC20[] memory _pooledTokens,
396       uint8[] memory decimals,
397       string memory lpTokenName,
398       string memory lpTokenSymbol,
399       uint256 _a,
400       uint256 _fee,
401       uint256 _adminFee,
402       address lpTokenTargetAddress
403:    ) external onlyOwner {

460:    function withdrawSwapAdminFees(bytes32 canonicalId) external onlyOwner {

469:    function setSwapAdminFee(bytes32 canonicalId, uint256 newAdminFee) external onlyOwner {

478:    function setSwapFee(bytes32 canonicalId, uint256 newSwapFee) external onlyOwner {

490     function rampA(
491       bytes32 canonicalId,
492       uint256 futureA,
493       uint256 futureTime
494:    ) external onlyOwner {

502:    function stopRampA(bytes32 canonicalId) external onlyOwner {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/StableSwapFacet.sol#L393-L403

File: contracts/contracts/core/connext/facets/BridgeFacet.sol

233:    function setPromiseRouter(address payable _promiseRouter) external onlyOwner {

242:    function setExecutor(address _executor) external onlyOwner {

250:    function setSponsorVault(address _sponsorVault) external onlyOwner {

389     function handle(
390       uint32 _origin,
391       uint32 _nonce,
392       bytes32 _sender,
393       bytes memory _message
394:    ) external onlyReplica onlyRemoteRouter(_origin, _sender) {

389     function handle(
390       uint32 _origin,
391       uint32 _nonce,
392       bytes32 _sender,
393       bytes memory _message
394:    ) external onlyReplica onlyRemoteRouter(_origin, _sender) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/BridgeFacet.sol#L233

File: contracts/contracts/core/connext/facets/AssetFacet.sol

100:    function setWrapper(address _wrapper) external onlyOwner {

112:    function setTokenRegistry(address _tokenRegistry) external onlyOwner {

132     function setupAsset(
133       ConnextMessage.TokenId calldata _canonical,
134       address _adoptedAssetId,
135       address _stableSwapPool
136:    ) external onlyOwner {

162:    function addStableSwapPool(ConnextMessage.TokenId calldata _canonical, address _stableSwapPool) external onlyOwner {

171:    function removeAssetId(bytes32 _canonicalId, address _adoptedAssetId) external onlyOwner {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/AssetFacet.sol#L100

File: contracts/contracts/core/connext/facets/PortalFacet.sol

57:     function setAavePool(address _aavePool) external onlyOwner {

65:     function setAavePortalFee(uint256 _aavePortalFeeNumerator) external onlyOwner {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/PortalFacet.sol#L57

File: contracts/contracts/core/connext/facets/RelayerFacet.sol

88:     function setRelayerFeeRouter(address _relayerFeeRouter) external onlyOwner {

101:    function addRelayer(address _relayer) external onlyOwner {

112:    function removeRelayer(address _relayer) external onlyOwner {

161:    function claim(address _recipient, bytes32[] calldata _transferIds) external onlyRelayerFeeRouter {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/RelayerFacet.sol#L88

File: contracts/contracts/core/connext/facets/ProposedOwnableFacet.sol

128:    function proposeRouterOwnershipRenunciation() public onlyOwner {

142:    function renounceRouterOwnership() public onlyOwner {

162:    function proposeAssetOwnershipRenunciation() public onlyOwner {

175:    function renounceAssetOwnership() public onlyOwner {

203:    function proposeNewOwner(address newlyProposed) public onlyOwner {

217:    function renounceOwnership() public onlyOwner {

236:    function acceptProposedOwner() public onlyProposed {

253:    function pause() public onlyOwner {

258:    function unpause() public onlyOwner {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/ProposedOwnableFacet.sol#L128

File: contracts/contracts/core/connext/facets/NomadFacet.sol

25:     function setXAppConnectionManager(address _xAppConnectionManager) external onlyOwner {

34:     function enrollRemoteRouter(uint32 _domain, bytes32 _router) external onlyOwner {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/NomadFacet.sol#L25

File: contracts/contracts/core/connext/facets/RoutersFacet.sol

259     function setupRouter(
260       address router,
261       address owner,
262       address recipient
263:    ) external onlyOwner {

293:    function removeRouter(address router) external onlyOwner {

331:    function setMaxRoutersPerTransfer(uint256 _newMaxRouters) external onlyOwner {

345:    function setLiquidityFeeNumerator(uint256 _numerator) external onlyOwner {

361:    function approveRouterForPortal(address _router) external onlyOwner {

375:    function unapproveRouterForPortal(address _router) external onlyOwner {

393:    function setRouterRecipient(address router, address recipient) external onlyRouterOwner(router) {

410:    function proposeRouterOwner(address router, address proposed) external onlyRouterOwner(router) {

430:    function acceptProposedRouterOwner(address router) external onlyProposedRouterOwner(router) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/facets/RoutersFacet.sol#L259-L263

File: contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol

142     function setDexPriceInfo(
143       address _token,
144       address _baseToken,
145       address _lpToken,
146       bool _active
147:    ) external onlyAdmin {

158:    function setDirectPrice(address _token, uint256 _price) external onlyAdmin {

163:    function setV1PriceOracle(address _v1PriceOracle) external onlyAdmin {

168:    function setAdmin(address newAdmin) external onlyAdmin {

175:    function setAggregators(address[] calldata tokenAddresses, address[] calldata sources) external onlyAdmin {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ConnextPriceOracle.sol#L142-L147

File: contracts/contracts/core/connext/helpers/Executor.sol

113:    function execute(ExecutorArgs memory _args) external payable override onlyConnext returns (bool, bytes memory) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/Executor.sol#L113

File: contracts/contracts/core/connext/helpers/LPToken.sol

34:     function mint(address recipient, uint256 amount) external onlyOwner {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/LPToken.sol#L34

File: contracts/contracts/core/connext/helpers/StableSwap.sol

440:    function withdrawAdminFees() external onlyOwner {

448:    function setAdminFee(uint256 newAdminFee) external onlyOwner {

456:    function setSwapFee(uint256 newSwapFee) external onlyOwner {

467:    function rampA(uint256 futureA, uint256 futureTime) external onlyOwner {

474:    function stopRampA() external onlyOwner {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/StableSwap.sol#L440

File: contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol

77:     function __ProposedOwnable_init() internal onlyInitializing {

81:     function __ProposedOwnable_init_unchained() internal onlyInitializing {

155:    function proposeRouterOwnershipRenunciation() public virtual onlyOwner {

169:    function renounceRouterOwnership() public virtual onlyOwner {

197:    function proposeAssetOwnershipRenunciation() public virtual onlyOwner {

211:    function renounceAssetOwnership() public virtual onlyOwner {

239:    function proposeNewOwner(address newlyProposed) public virtual onlyOwner {

253:    function renounceOwnership() public virtual onlyOwner {

272:    function acceptProposedOwner() public virtual onlyProposed {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/ProposedOwnableUpgradeable.sol#L77

File: contracts/contracts/core/connext/helpers/SponsorVault.sol

138:    function setConnext(address _connext) external onlyOwner {

147:    function setRate(uint32 _originDomain, Rate calldata _rate) external onlyOwner {

159:    function setRelayerFeeCap(uint256 _relayerFeeCap) external onlyOwner {

168:    function setGasTokenOracle(address _gasTokenOracle) external onlyOwner {

178:    function setTokenExchange(address _token, address payable _tokenExchange) external onlyOwner {

196     function reimburseLiquidityFees(
197       address _token,
198       uint256 _liquidityFee,
199       address _receiver
200:    ) external override onlyConnext returns (uint256) {

234     function reimburseRelayerFees(
235       uint32 _originDomain,
236       address payable _to,
237       uint256 _originRelayerFee
238:    ) external override onlyConnext {

286     function withdraw(
287       address _token,
288       address _receiver,
289       uint256 _amount
290:    ) external onlyOwner {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/connext/helpers/SponsorVault.sol#L138

File: contracts/contracts/core/promise/PromiseRouter.sol

155:    function setConnext(address _connext) external onlyOwner {

170     function send(
171       uint32 _domain,
172       bytes32 _transferId,
173       address _callbackAddress,
174       bool _returnSuccess,
175       bytes calldata _returnData
176:    ) external onlyConnext {

205     function handle(
206       uint32 _origin,
207       uint32 _nonce,
208       bytes32 _sender,
209       bytes memory _message
210:    ) external override onlyReplica onlyRemoteRouter(_origin, _sender) {

205     function handle(
206       uint32 _origin,
207       uint32 _nonce,
208       bytes32 _sender,
209       bytes memory _message
210:    ) external override onlyReplica onlyRemoteRouter(_origin, _sender) {

268:    function initCallbackFee(bytes32 _transferId) external payable onlyConnext {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/promise/PromiseRouter.sol#L155

File: contracts/contracts/core/relayer-fee/RelayerFeeRouter.sol

89:     function setConnext(address _connext) external onlyOwner {

102     function send(
103       uint32 _domain,
104       address _recipient,
105       bytes32[] calldata _transferIds
106:    ) external onlyConnext {

130     function handle(
131       uint32 _origin,
132       uint32 _nonce,
133       bytes32 _sender,
134       bytes memory _message
135:    ) external override onlyReplica onlyRemoteRouter(_origin, _sender) {

130     function handle(
131       uint32 _origin,
132       uint32 _nonce,
133       bytes32 _sender,
134       bytes memory _message
135:    ) external override onlyReplica onlyRemoteRouter(_origin, _sender) {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/relayer-fee/RelayerFeeRouter.sol#L89

File: contracts/contracts/core/shared/ProposedOwnable.sol

109:    function proposeNewOwner(address newlyProposed) public virtual onlyOwner {

123:    function renounceOwnership() public virtual onlyOwner {

142:    function acceptProposedOwner() public virtual onlyProposed {

180:    function __ProposedOwnable_init() internal onlyInitializing {

184:    function __ProposedOwnable_init_unchained() internal onlyInitializing {

https://github.com/code-423n4/2022-06-connext/blob/4dd6149748b635f95460d4c3924c7e3fb6716967/contracts/contracts/core/shared/ProposedOwnable.sol#L109

itsmetechjay commented 2 years ago

Warden created this issue as a placeholder, because their submission was too large for the contest form. They then emailed their md file to our team on 06/19/2022 at 10:16am central. I've updated this issue with their md file content.