Skip to content

Instantly share code, notes, and snippets.

@misirov
Created November 27, 2023 19:10
Show Gist options
  • Save misirov/cb47dba58011853ecb7e4ee77db6c4da to your computer and use it in GitHub Desktop.
Save misirov/cb47dba58011853ecb7e4ee77db6c4da to your computer and use it in GitHub Desktop.
4nalyzer findings

Report ERC1155A

Files analyzed

Analyzed

'ERC1155A.sol'
'aERC20.sol'

Gas Optimizations

Issue Instances
GAS-1 Using bools for storage incurs overhead 1
GAS-2 Cache array length outside of loop 6
GAS-3 For Operations that will not overflow, you could use unchecked 49
GAS-4 Don't initialize variables with default value 5
GAS-5 Functions guaranteed to revert when called by normal users can be marked payable 2
GAS-6 Use != 0 instead of > 0 for unsigned integer comparison 3

[GAS-1] Using bools for storage incurs overhead

Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas), and to avoid Gsset (20000 gas) when changing from ‘false’ to ‘true’, after having been ‘true’ in the past. See source.

Instances (1):

File: ERC1155A.sol

31:     mapping(address => mapping(address => bool)) public isApprovedForAll;

[GAS-2] Cache array length outside of loop

If not cached, the solidity compiler will always read the length of the array during each iteration. That is, if it is a storage array, this is an extra sload operation (100 additional extra gas for each iteration except for the first) and if it is a memory array, this is an extra mload operation (3 additional gas for each iteration except for the first).

Instances (6):

File: ERC1155A.sol

164:         for (uint256 i = 0; i < owners.length; ++i) {

205:         for (uint256 i; i < ids.length; ++i) {

222:         for (uint256 i; i < ids.length; ++i) {

242:         for (uint256 i; i < ids.length; ++i) {

269:         for (uint256 i = 0; i < ids.length; ++i) {

288:         for (uint256 i = 0; i < ids.length; ++i) {

[GAS-3] For Operations that will not overflow, you could use unchecked

Instances (49):

File: ERC1155A.sol

132:         for (uint256 i; i < len; ++i) {

132:         for (uint256 i; i < len; ++i) {

138:                 allowances[from][to][id] -= amount;

141:             balanceOf[from][id] -= amount;

142:             balanceOf[to][id] += amount;

164:         for (uint256 i = 0; i < owners.length; ++i) {

164:         for (uint256 i = 0; i < owners.length; ++i) {

187:         _setApprovalForOne(owner, spender, id, allowance(owner, spender, id) + addedValue);

205:         for (uint256 i; i < ids.length; ++i) {

205:         for (uint256 i; i < ids.length; ++i) {

222:         for (uint256 i; i < ids.length; ++i) {

222:         for (uint256 i; i < ids.length; ++i) {

224:             _setApprovalForOne(owner, spender, id, allowance(owner, spender, id) + addedValues[i]);

242:         for (uint256 i; i < ids.length; ++i) {

242:         for (uint256 i; i < ids.length; ++i) {

269:         for (uint256 i = 0; i < ids.length; ++i) {

269:         for (uint256 i = 0; i < ids.length; ++i) {

288:         for (uint256 i = 0; i < ids.length; ++i) {

288:         for (uint256 i = 0; i < ids.length; ++i) {

364:         return interfaceId == 0x01ffc9a7 // ERC165 Interface ID for ERC165

364:         return interfaceId == 0x01ffc9a7 // ERC165 Interface ID for ERC165

365:             || interfaceId == 0xd9b67a26 // ERC165 Interface ID for ERC1155

365:             || interfaceId == 0xd9b67a26 // ERC165 Interface ID for ERC1155

366:             || interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI

366:             || interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI

387:         balanceOf[from][id] -= amount;

388:         balanceOf[to][id] += amount;

411:         _setApprovalForOne(owner, operator, id, currentAllowance - subtractedValue);

430:                         INTERNAL MINT/BURN LOGIC

435:         balanceOf[to][id] += amount;

436:         _totalSupply[id] += amount;

454:         uint256 idsLength = ids.length; // Saves MLOADs.

454:         uint256 idsLength = ids.length; // Saves MLOADs.

458:         for (uint256 i = 0; i < idsLength; ++i) {

458:         for (uint256 i = 0; i < idsLength; ++i) {

459:             balanceOf[to][ids[i]] += amounts[i];

460:             _totalSupply[ids[i]] += amounts[i];

479:         uint256 idsLength = ids.length; // Saves MLOADs.

479:         uint256 idsLength = ids.length; // Saves MLOADs.

491:         for (uint256 i = 0; i < idsLength; ++i) {

491:         for (uint256 i = 0; i < idsLength; ++i) {

497:                 allowances[from][operator][id] -= amount;

500:             balanceOf[from][id] -= amount;

501:             _totalSupply[id] -= amount;

513:             allowances[from][operator][id] -= amount; // Deduct the burned amount from the allowance

513:             allowances[from][operator][id] -= amount; // Deduct the burned amount from the allowance

513:             allowances[from][operator][id] -= amount; // Deduct the burned amount from the allowance

517:         balanceOf[from][id] -= amount;

518:         _totalSupply[id] -= amount;

[GAS-4] Don't initialize variables with default value

Instances (5):

File: ERC1155A.sol

164:         for (uint256 i = 0; i < owners.length; ++i) {

269:         for (uint256 i = 0; i < ids.length; ++i) {

288:         for (uint256 i = 0; i < ids.length; ++i) {

458:         for (uint256 i = 0; i < idsLength; ++i) {

491:         for (uint256 i = 0; i < idsLength; ++i) {

[GAS-5] 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.

Instances (2):

File: aERC20.sol

28:     function mint(address owner, uint256 amount) external override onlyTokenSplitter {

33:     function burn(address owner, address operator, uint256 amount) external override onlyTokenSplitter {

[GAS-6] Use != 0 instead of > 0 for unsigned integer comparison

Instances (3):

File: ERC1155A.sol

350:         return _totalSupply[id] > 0;

538:         if (to.code.length > 0) {

572:         if (to.code.length > 0) {



Report superform-core

Files analyzed

Not analized

  • superform-core/src/crosschain-data/extensions/CoreStateRegistry.sol
  • payments/PaymentHelper.sol

Analyzed

  'BaseForm.sol',
  'BaseRouter.sol',
  'BaseRouterImplementation.sol',
  'EmergencyQueue.sol',
  'SuperPositions.sol',
  'SuperformFactory.sol',
  'SuperformRouter.sol',
  'types/DataTypes.sol',
  'settings/SuperRBAC.sol',
  'settings/SuperRegistry.sol',
  'payments/PayMaster.sol',
  'libraries/ArrayCastLib.sol',
  'libraries/DataLib.sol',
  'libraries/PayloadUpdaterLib.sol',
  'libraries/ProofLib.sol',
  'forms/ERC4626Form.sol',
  'forms/ERC4626FormImplementation.sol',
  'forms/ERC4626KYCDaoForm.sol',
  'forms/ERC4626TimelockForm.sol',
  'crosschain-liquidity/BridgeValidator.sol',
  'crosschain-liquidity/DstSwapper.sol',
  'crosschain-liquidity/LiquidityHandler.sol',
  'crosschain-liquidity/socket/SocketOneInchValidator.sol',
  'crosschain-liquidity/socket/SocketValidator.sol',
  'crosschain-liquidity/lifi/LiFiValidator.sol',
  'crosschain-data/BaseStateRegistry.sol',
  'crosschain-data/BroadcastRegistry.sol',
  'crosschain-data/utils/PayloadHelper.sol',
  'crosschain-data/utils/QuorumManager.sol',
  'crosschain-data/extensions/TimelockStateRegistry.sol',
  'crosschain-data/adapters/wormhole/specialized-relayer/WormholeSRImplementation.sol',
  'crosschain-data/adapters/wormhole/automatic-relayer/WormholeARImplementation.sol',
  'crosschain-data/adapters/layerzero/LayerzeroImplementation.sol',
  'crosschain-data/adapters/hyperlane/HyperlaneImplementation.sol'

Gas Optimizations

Issue Instances
GAS-1 Using bools for storage incurs overhead 7
GAS-2 Cache array length outside of loop 23
GAS-3 For Operations that will not overflow, you could use unchecked 349
GAS-4 Functions guaranteed to revert when called by normal users can be marked payable 37
GAS-5 ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too) 1
GAS-6 Using private rather than public for constants, saves gas 34

[GAS-1] Using bools for storage incurs overhead

Use uint256(1) and uint256(2) for true/false to avoid a Gwarmaccess (100 gas), and to avoid Gsset (20000 gas) when changing from ‘false’ to ‘true’, after having been ‘true’ in the past. See source.

Instances (7):

File: SuperPositions.sol

27:     bool public dynamicURIFrozen;
File: SuperformFactory.sol

33:     mapping(uint256 superformId => bool superformIdExists) public isSuperform;
File: crosschain-data/adapters/hyperlane/HyperlaneImplementation.sol

26:     mapping(bytes32 => bool) public processedMessages;
File: crosschain-data/adapters/layerzero/LayerzeroImplementation.sol

24:     mapping(uint16 => mapping(uint64 => bool)) public isValid;
File: crosschain-data/adapters/wormhole/automatic-relayer/WormholeARImplementation.sol

27:     mapping(bytes32 => bool) public processedMessages;
File: crosschain-data/adapters/wormhole/specialized-relayer/WormholeSRImplementation.sol

31:     mapping(bytes32 => bool) public processedMessages;
File: settings/SuperRegistry.sol

85:     mapping(uint8 ambId => bool isBroadcastAMB) public isBroadcastAMB;

[GAS-2] Cache array length outside of loop

If not cached, the solidity compiler will always read the length of the array during each iteration. That is, if it is a storage array, this is an extra sload operation (100 additional extra gas for each iteration except for the first) and if it is a memory array, this is an extra mload operation (3 additional gas for each iteration except for the first).

Instances (23):

File: BaseRouterImplementation.sol

220:             new bool[](req_.superformData.amounts.length),

258:         uint256 len = req_.superformsData.superformIds.length;

431:             new bool[](req_.superformData.superformIds.length),

432:             new bool[](req_.superformData.superformIds.length),

468:             new bool[](req_.superformsData.amounts.length),

469:             new bool[](req_.superformsData.amounts.length),

643:         v.len = vaultData_.superformIds.length;

741:         uint256 len = superforms.length;

819:         uint256 len = superformsData_.amounts.length;

820:         uint256 lenSuperforms = superformsData_.superformIds.length;

821:         uint256 liqRequestsLen = superformsData_.liqRequests.length;

833:         if (!(lenSuperforms == len && lenSuperforms == superformsData_.maxSlippages.length)) {
File: EmergencyQueue.sol

101:         for (uint256 i; i < ids_.length; ++i) {
File: SuperPositions.sol

76:             uint256 len = superformIds.length;

299:         for (uint256 i; i < superformIds_.length; ++i) {
File: SuperformFactory.sol

93:         forms_ = formImplementations.length;

98:         superforms_ = superforms.length;

129:         uint256 len = superformIds_.length;

145:         uint256 len = superformIds_.length;
File: crosschain-liquidity/DstSwapper.sol

419:             if (index_ >= data.superformIds.length) {
File: libraries/ArrayCastLib.sol

43:             new bool[](superformIds.length),

44:             new bool[](superformIds.length),
File: libraries/DataLib.sol

63:         uint256 len = superformIds_.length;

[GAS-3] For Operations that will not overflow, you could use unchecked

Instances (349):

File: BaseRouterImplementation.sol

4: import { BaseRouter } from "./BaseRouter.sol";

5: import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";

5: import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";

5: import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";

5: import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";

6: import { SafeERC20 } from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";

6: import { SafeERC20 } from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";

6: import { SafeERC20 } from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";

6: import { SafeERC20 } from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";

6: import { SafeERC20 } from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";

6: import { SafeERC20 } from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";

7: import { IBaseStateRegistry } from "./interfaces/IBaseStateRegistry.sol";

7: import { IBaseStateRegistry } from "./interfaces/IBaseStateRegistry.sol";

8: import { IBaseRouterImplementation } from "./interfaces/IBaseRouterImplementation.sol";

8: import { IBaseRouterImplementation } from "./interfaces/IBaseRouterImplementation.sol";

9: import { IPayMaster } from "./interfaces/IPayMaster.sol";

9: import { IPayMaster } from "./interfaces/IPayMaster.sol";

10: import { IPaymentHelper } from "./interfaces/IPaymentHelper.sol";

10: import { IPaymentHelper } from "./interfaces/IPaymentHelper.sol";

11: import { ISuperformFactory } from "./interfaces/ISuperformFactory.sol";

11: import { ISuperformFactory } from "./interfaces/ISuperformFactory.sol";

12: import { IBaseForm } from "./interfaces/IBaseForm.sol";

12: import { IBaseForm } from "./interfaces/IBaseForm.sol";

13: import { IBridgeValidator } from "./interfaces/IBridgeValidator.sol";

13: import { IBridgeValidator } from "./interfaces/IBridgeValidator.sol";

14: import { ISuperPositions } from "./interfaces/ISuperPositions.sol";

14: import { ISuperPositions } from "./interfaces/ISuperPositions.sol";

15: import { DataLib } from "./libraries/DataLib.sol";

15: import { DataLib } from "./libraries/DataLib.sol";

16: import { Error } from "./libraries/Error.sol";

16: import { Error } from "./libraries/Error.sol";

17: import { IPermit2 } from "./vendor/dragonfly-xyz/IPermit2.sol";

17: import { IPermit2 } from "./vendor/dragonfly-xyz/IPermit2.sol";

17: import { IPermit2 } from "./vendor/dragonfly-xyz/IPermit2.sol";

17: import { IPermit2 } from "./vendor/dragonfly-xyz/IPermit2.sol";

18: import "./crosschain-liquidity/LiquidityHandler.sol";

18: import "./crosschain-liquidity/LiquidityHandler.sol";

18: import "./crosschain-liquidity/LiquidityHandler.sol";

19: import "./types/DataTypes.sol";

19: import "./types/DataTypes.sol";

149:         vars.currentPayloadId = ++payloadIds;

149:         vars.currentPayloadId = ++payloadIds;

243:         vars.currentPayloadId = ++payloadIds;

243:         vars.currentPayloadId = ++payloadIds;

268:         for (uint256 j; j < len; ++j) {

268:         for (uint256 j; j < len; ++j) {

373:         vars.currentPayloadId = ++payloadIds;

373:         vars.currentPayloadId = ++payloadIds;

460:         vars.currentPayloadId = ++payloadIds;

460:         vars.currentPayloadId = ++payloadIds;

653:         for (uint256 i; i < v.len; ++i) {

653:         for (uint256 i; i < v.len; ++i) {

743:         for (uint256 i; i < len; ++i) {

743:         for (uint256 i; i < len; ++i) {

839:         for (uint256 i; i < len; ++i) {

839:         for (uint256 i; i < len; ++i) {

865:         uint256 residualPayment = address(this).balance - _balanceBefore;

972:         for (uint256 i; i < v.len; ++i) {

972:         for (uint256 i; i < v.len; ++i) {

989:             for (uint256 i; i < v.len; ++i) {

989:             for (uint256 i; i < v.len; ++i) {

1003:                 v.totalAmount += v.approvalAmounts[i];

1044:             for (uint256 j; j < v.targetLen; ++j) {

1044:             for (uint256 j; j < v.targetLen; ++j) {
File: EmergencyQueue.sol

85:         ++queueCounter;

85:         ++queueCounter;

101:         for (uint256 i; i < ids_.length; ++i) {

101:         for (uint256 i; i < ids_.length; ++i) {
File: SuperPositions.sol

77:             for (uint256 i; i < len; ++i) {

77:             for (uint256 i; i < len; ++i) {

299:         for (uint256 i; i < superformIds_.length; ++i) {

299:         for (uint256 i; i < superformIds_.length; ++i) {

331:         string memory symbol = string(abi.encodePacked("aERC20-", IBaseForm(superform).superformYieldTokenSymbol()));

338:             abi.encode(CHAIN_ID, ++xChainPayloadCounter, id, name, symbol, decimal)

338:             abi.encode(CHAIN_ID, ++xChainPayloadCounter, id, name, symbol, decimal)
File: SuperformFactory.sol

132:         for (uint256 i; i < len; ++i) {

132:         for (uint256 i; i < len; ++i) {

148:         for (uint256 i; i < len; ++i) {

148:         for (uint256 i; i < len; ++i) {

205:         ++superformCounter;

205:         ++superformCounter;

244:                 abi.encode(CHAIN_ID, ++xChainPayloadCounter, formImplementationId_, status_)

244:                 abi.encode(CHAIN_ID, ++xChainPayloadCounter, formImplementationId_, status_)
File: SuperformRouter.sol

25:         uint256 balanceBefore = address(this).balance - msg.value;

37:         uint256 balanceBefore = address(this).balance - msg.value;

49:         uint256 balanceBefore = address(this).balance - msg.value;

61:         uint256 balanceBefore = address(this).balance - msg.value;

74:         uint256 balanceBefore = address(this).balance - msg.value;

77:         for (uint256 i; i < len; ++i) {

77:         for (uint256 i; i < len; ++i) {

97:         uint256 balanceBefore = address(this).balance - msg.value;

99:         for (uint256 i; i < len; ++i) {

99:         for (uint256 i; i < len; ++i) {

118:         uint256 balanceBefore = address(this).balance - msg.value;

130:         uint256 balanceBefore = address(this).balance - msg.value;

142:         uint256 balanceBefore = address(this).balance - msg.value;

154:         uint256 balanceBefore = address(this).balance - msg.value;

166:         uint256 balanceBefore = address(this).balance - msg.value;

169:         for (uint256 i; i < len; ++i) {

169:         for (uint256 i; i < len; ++i) {

189:         uint256 balanceBefore = address(this).balance - msg.value;

192:         for (uint256 i; i < len; ++i) {

192:         for (uint256 i; i < len; ++i) {
File: crosschain-data/BaseStateRegistry.sol

110:             ++messageQuorum[proofHash];

110:             ++messageQuorum[proofHash];

115:             ++payloadsCount;

115:             ++payloadsCount;

148:         if (len - 1 < _getQuorum(dstChainId_)) {

165:             for (uint8 i = 1; i < len; ++i) {

165:             for (uint8 i = 1; i < len; ++i) {

170:                 if (i - 1 != 0 && ambIds_[i] <= ambIds_[i - 1]) {

170:                 if (i - 1 != 0 && ambIds_[i] <= ambIds_[i - 1]) {
File: crosschain-data/BroadcastRegistry.sol

108:         ++payloadsCount;

108:         ++payloadsCount;
File: crosschain-data/adapters/wormhole/automatic-relayer/WormholeARImplementation.sol

121:         address, /*srcSender_*/

121:         address, /*srcSender_*/

121:         address, /*srcSender_*/

121:         address, /*srcSender_*/
File: crosschain-data/adapters/wormhole/specialized-relayer/WormholeSRImplementation.sol

121:         bytes memory, /*message_*/

121:         bytes memory, /*message_*/

121:         bytes memory, /*message_*/

121:         bytes memory, /*message_*/

122:         bytes memory /*extraData_*/

122:         bytes memory /*extraData_*/

122:         bytes memory /*extraData_*/

122:         bytes memory /*extraData_*/

138:         address, /*srcSender_*/

138:         address, /*srcSender_*/

138:         address, /*srcSender_*/

138:         address, /*srcSender_*/

140:         bytes memory /*extraData_*/

140:         bytes memory /*extraData_*/

140:         bytes memory /*extraData_*/

140:         bytes memory /*extraData_*/

166:         (bool success,) = payable(relayer).call{ value: msg.value - msgFee }("");
File: crosschain-data/extensions/TimelockStateRegistry.sol

90:         ++timelockPayloadCounter;

90:         ++timelockPayloadCounter;
File: crosschain-data/utils/PayloadHelper.sol

347:         for (uint256 i; i < len; ++i) {

347:         for (uint256 i; i < len; ++i) {
File: crosschain-liquidity/DstSwapper.sol

168:         for (uint256 i; i < len; ++i) {

168:         for (uint256 i; i < len; ++i) {

226:         for (uint256 i; i < len; ++i) {

226:         for (uint256 i; i < len; ++i) {

327:         v.balanceDiff = v.balanceAfter - v.balanceBefore;

339:         if (v.balanceDiff < ((v.expAmount * (10_000 - v.maxSlippage)) / 10_000)) {

339:         if (v.balanceDiff < ((v.expAmount * (10_000 - v.maxSlippage)) / 10_000)) {

339:         if (v.balanceDiff < ((v.expAmount * (10_000 - v.maxSlippage)) / 10_000)) {
File: crosschain-liquidity/lifi/LiFiValidator.sol

33:             string memory, /*bridge*/

33:             string memory, /*bridge*/

33:             string memory, /*bridge*/

33:             string memory, /*bridge*/

36:             uint256, /*amount*/

36:             uint256, /*amount*/

36:             uint256, /*amount*/

36:             uint256, /*amount*/

37:             uint256, /*minAmount*/

37:             uint256, /*minAmount*/

37:             uint256, /*minAmount*/

37:             uint256, /*minAmount*/

39:             bool, /*hasSourceSwaps*/

39:             bool, /*hasSourceSwaps*/

39:             bool, /*hasSourceSwaps*/

39:             bool, /*hasSourceSwaps*/

126:             string memory, /*bridge*/

126:             string memory, /*bridge*/

126:             string memory, /*bridge*/

126:             string memory, /*bridge*/

127:             address, /*sendingAssetId*/

127:             address, /*sendingAssetId*/

127:             address, /*sendingAssetId*/

127:             address, /*sendingAssetId*/

128:             address, /*receiver*/

128:             address, /*receiver*/

128:             address, /*receiver*/

128:             address, /*receiver*/

130:             uint256, /*minAmount*/

130:             uint256, /*minAmount*/

130:             uint256, /*minAmount*/

130:             uint256, /*minAmount*/

131:             uint256, /*destinationChainId*/

131:             uint256, /*destinationChainId*/

131:             uint256, /*destinationChainId*/

131:             uint256, /*destinationChainId*/

132:             bool, /*hasSourceSwaps*/

132:             bool, /*hasSourceSwaps*/

132:             bool, /*hasSourceSwaps*/

132:             bool, /*hasSourceSwaps*/

133:             bool /*hasDestinationCall*/

133:             bool /*hasDestinationCall*/

133:             bool /*hasDestinationCall*/

133:             bool /*hasDestinationCall*/

153:             string memory, /*bridge*/

153:             string memory, /*bridge*/

153:             string memory, /*bridge*/

153:             string memory, /*bridge*/

154:             address, /*sendingAssetId*/

154:             address, /*sendingAssetId*/

154:             address, /*sendingAssetId*/

154:             address, /*sendingAssetId*/

155:             address, /*receiver*/

155:             address, /*receiver*/

155:             address, /*receiver*/

155:             address, /*receiver*/

156:             uint256, /*amount*/

156:             uint256, /*amount*/

156:             uint256, /*amount*/

156:             uint256, /*amount*/

157:             uint256, /*minAmount*/

157:             uint256, /*minAmount*/

157:             uint256, /*minAmount*/

157:             uint256, /*minAmount*/

158:             uint256, /*destinationChainId*/

158:             uint256, /*destinationChainId*/

158:             uint256, /*destinationChainId*/

158:             uint256, /*destinationChainId*/

159:             bool, /*hasSourceSwaps*/

159:             bool, /*hasSourceSwaps*/

159:             bool, /*hasSourceSwaps*/

159:             bool, /*hasSourceSwaps*/

160:             bool /*hasDestinationCall*/

160:             bool /*hasDestinationCall*/

160:             bool /*hasDestinationCall*/

160:             bool /*hasDestinationCall*/

244:             _slice(callData, 4, callData.length - 4), (bytes32, string, string, address, uint256, LibSwap.SwapData[])

249:         receivingAssetId = swapData[swapData.length - 1].receivingAssetId;
File: crosschain-liquidity/socket/SocketOneInchValidator.sol

50:         bool /*genericSwapDisallowed_*/

50:         bool /*genericSwapDisallowed_*/

50:         bool /*genericSwapDisallowed_*/

50:         bool /*genericSwapDisallowed_*/
File: crosschain-liquidity/socket/SocketValidator.sol

74:         bool /*genericSwapDisallowed_*/

74:         bool /*genericSwapDisallowed_*/

74:         bool /*genericSwapDisallowed_*/

74:         bool /*genericSwapDisallowed_*/

85:     function decodeDstSwap(bytes calldata /*txData_*/ )

85:     function decodeDstSwap(bytes calldata /*txData_*/ )

85:     function decodeDstSwap(bytes calldata /*txData_*/ )

85:     function decodeDstSwap(bytes calldata /*txData_*/ )

89:         returns (address, /*token_*/ uint256 /*amount_*/ )

89:         returns (address, /*token_*/ uint256 /*amount_*/ )

89:         returns (address, /*token_*/ uint256 /*amount_*/ )

89:         returns (address, /*token_*/ uint256 /*amount_*/ )

89:         returns (address, /*token_*/ uint256 /*amount_*/ )

89:         returns (address, /*token_*/ uint256 /*amount_*/ )

89:         returns (address, /*token_*/ uint256 /*amount_*/ )

89:         returns (address, /*token_*/ uint256 /*amount_*/ )

94:     function decodeSwapOutputToken(bytes calldata /*txData_*/ ) external pure override returns (address /*token_*/ ) {

94:     function decodeSwapOutputToken(bytes calldata /*txData_*/ ) external pure override returns (address /*token_*/ ) {

94:     function decodeSwapOutputToken(bytes calldata /*txData_*/ ) external pure override returns (address /*token_*/ ) {

94:     function decodeSwapOutputToken(bytes calldata /*txData_*/ ) external pure override returns (address /*token_*/ ) {

94:     function decodeSwapOutputToken(bytes calldata /*txData_*/ ) external pure override returns (address /*token_*/ ) {

94:     function decodeSwapOutputToken(bytes calldata /*txData_*/ ) external pure override returns (address /*token_*/ ) {

94:     function decodeSwapOutputToken(bytes calldata /*txData_*/ ) external pure override returns (address /*token_*/ ) {

94:     function decodeSwapOutputToken(bytes calldata /*txData_*/ ) external pure override returns (address /*token_*/ ) {
File: forms/ERC4626Form.sol

12:     uint8 constant stateRegistryId = 1; // CoreStateRegistry

12:     uint8 constant stateRegistryId = 1; // CoreStateRegistry

27:         address /*srcSender_*/

27:         address /*srcSender_*/

27:         address /*srcSender_*/

27:         address /*srcSender_*/

75:     function _emergencyWithdraw(address, /*srcSender_*/ address refundAddress_, uint256 amount_) internal override {

75:     function _emergencyWithdraw(address, /*srcSender_*/ address refundAddress_, uint256 amount_) internal override {

75:     function _emergencyWithdraw(address, /*srcSender_*/ address refundAddress_, uint256 amount_) internal override {

75:     function _emergencyWithdraw(address, /*srcSender_*/ address refundAddress_, uint256 amount_) internal override {
File: forms/ERC4626FormImplementation.sol

87:         return IERC4626(vault).convertToAssets(10 ** vaultDecimals);

87:         return IERC4626(vault).convertToAssets(10 ** vaultDecimals);

108:         return IERC4626(vault).previewRedeem(10 ** vaultDecimals);

108:         return IERC4626(vault).previewRedeem(10 ** vaultDecimals);

133:         return string(abi.encodePacked("SUP-", IERC20Metadata(vault).symbol()));

216:         vars.assetDifference = IERC20(vars.asset).balanceOf(address(this)) - vars.balanceBefore;

324:         address, /*srcSender_*/

324:         address, /*srcSender_*/

324:         address, /*srcSender_*/

324:         address, /*srcSender_*/
File: forms/ERC4626KYCDaoForm.sol

11:     uint8 constant stateRegistryId = 1; // CoreStateRegistry

11:     uint8 constant stateRegistryId = 1; // CoreStateRegistry

50:         InitSingleVaultData memory, /*singleVaultData_*/

50:         InitSingleVaultData memory, /*singleVaultData_*/

50:         InitSingleVaultData memory, /*singleVaultData_*/

50:         InitSingleVaultData memory, /*singleVaultData_*/

51:         address, /*srcSender_*/

51:         address, /*srcSender_*/

51:         address, /*srcSender_*/

51:         address, /*srcSender_*/

52:         uint64 /*srcChainId_*/

52:         uint64 /*srcChainId_*/

52:         uint64 /*srcChainId_*/

52:         uint64 /*srcChainId_*/

57:         returns (uint256 /*dstAmount*/ )

57:         returns (uint256 /*dstAmount*/ )

57:         returns (uint256 /*dstAmount*/ )

57:         returns (uint256 /*dstAmount*/ )

77:         InitSingleVaultData memory, /*singleVaultData_*/

77:         InitSingleVaultData memory, /*singleVaultData_*/

77:         InitSingleVaultData memory, /*singleVaultData_*/

77:         InitSingleVaultData memory, /*singleVaultData_*/

78:         address, /*srcSender_*/

78:         address, /*srcSender_*/

78:         address, /*srcSender_*/

78:         address, /*srcSender_*/

79:         uint64 /*srcChainId_*/

79:         uint64 /*srcChainId_*/

79:         uint64 /*srcChainId_*/

79:         uint64 /*srcChainId_*/

84:         returns (uint256 /*dstAmount*/ )

84:         returns (uint256 /*dstAmount*/ )

84:         returns (uint256 /*dstAmount*/ )

84:         returns (uint256 /*dstAmount*/ )
File: forms/ERC4626TimelockForm.sol

15:     uint8 constant stateRegistryId = 2; // TimelockStateRegistry

15:     uint8 constant stateRegistryId = 2; // TimelockStateRegistry

124:         address /*srcSender_*/

124:         address /*srcSender_*/

124:         address /*srcSender_*/

124:         address /*srcSender_*/

190:     function _emergencyWithdraw(address, /*srcSender_*/ address refundAddress_, uint256 amount_) internal override {

190:     function _emergencyWithdraw(address, /*srcSender_*/ address refundAddress_, uint256 amount_) internal override {

190:     function _emergencyWithdraw(address, /*srcSender_*/ address refundAddress_, uint256 amount_) internal override {

190:     function _emergencyWithdraw(address, /*srcSender_*/ address refundAddress_, uint256 amount_) internal override {

205:         lockedTill_ = block.timestamp + v.getLockPeriod();
File: libraries/DataLib.sol

66:         for (uint256 i; i < len; ++i) {

66:         for (uint256 i; i < len; ++i) {
File: libraries/PayloadUpdaterLib.sol

21:         uint256 minAmount = (maxAmount_ * (10_000 - slippage_)) / 10_000;

21:         uint256 minAmount = (maxAmount_ * (10_000 - slippage_)) / 10_000;

21:         uint256 minAmount = (maxAmount_ * (10_000 - slippage_)) / 10_000;
File: payments/PayMaster.sol

93:         totalFeesPaid[user_] += msg.value;
File: settings/SuperRBAC.sol

171:                 "SUPER_RBAC", SYNC_REVOKE, abi.encode(++xChainPayloadCounter, role_, superRegistryAddressId_)

171:                 "SUPER_RBAC", SYNC_REVOKE, abi.encode(++xChainPayloadCounter, role_, superRegistryAddressId_)
File: settings/SuperRegistry.sol

271:         for (uint256 i; i < len; ++i) {

271:         for (uint256 i; i < len; ++i) {

300:         for (uint256 i; i < len; ++i) {

300:         for (uint256 i; i < len; ++i) {

327:         for (uint256 i; i < len; ++i) {

327:         for (uint256 i; i < len; ++i) {
File: types/DataTypes.sol

50:     LiqRequest[] liqRequests; // if length = 1; amount = sum(amounts) | else  amounts must match the amounts being sent

50:     LiqRequest[] liqRequests; // if length = 1; amount = sum(amounts) | else  amounts must match the amounts being sent

53:     bool[] retain4626s; // if true, we don't mint SuperPositions, and send the 4626 back to the user instead

53:     bool[] retain4626s; // if true, we don't mint SuperPositions, and send the 4626 back to the user instead

55:     bytes extraFormData; // extraFormData

55:     bytes extraFormData; // extraFormData

64:     LiqRequest liqRequest; // if length = 1; amount = sum(amounts)| else  amounts must match the amounts being sent

64:     LiqRequest liqRequest; // if length = 1; amount = sum(amounts)| else  amounts must match the amounts being sent

67:     bool retain4626; // if true, we don't mint SuperPositions, and send the 4626 back to the user instead

67:     bool retain4626; // if true, we don't mint SuperPositions, and send the 4626 back to the user instead

69:     bytes extraFormData; // extraFormData

69:     bytes extraFormData; // extraFormData

166:     uint256 txInfo; // tight packing of  TransactionType txType,  CallbackType flag  if multi/single vault, registry id,

166:     uint256 txInfo; // tight packing of  TransactionType txType,  CallbackType flag  if multi/single vault, registry id,

166:     uint256 txInfo; // tight packing of  TransactionType txType,  CallbackType flag  if multi/single vault, registry id,

168:     bytes params; // decoding txInfo will point to the right datatype of params. Refer PayloadHelper.sol

168:     bytes params; // decoding txInfo will point to the right datatype of params. Refer PayloadHelper.sol

[GAS-4] 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.

Instances (37):

File: EmergencyQueue.sol

96:     function executeQueuedWithdrawal(uint256 id_) external override onlyEmergencyAdmin {

100:     function batchExecuteQueuedWithdrawal(uint256[] calldata ids_) external override onlyEmergencyAdmin {
File: SuperPositions.sol

120:     function updateTxHistory(uint256 payloadId_, uint256 txInfo_) external override onlyRouter {

125:     function mintSingle(address srcSender_, uint256 id_, uint256 amount_) external override onlyMinter(id_) {

143:     function burnSingle(address srcSender_, uint256 id_, uint256 amount_) external override onlyRouter {

269:     function setDynamicURI(string memory dynamicURI_, bool freeze_) external override onlyProtocolAdmin {
File: crosschain-data/BaseStateRegistry.sol

104:     function receivePayload(uint64 srcChainId_, bytes memory message_) external override onlyValidAmbImplementation {
File: crosschain-data/BroadcastRegistry.sol

115:     function processPayload(uint256 payloadId) external override onlyProcessor {
File: crosschain-data/adapters/hyperlane/HyperlaneImplementation.sol

75:     function setHyperlaneConfig(IMailbox mailbox_, IInterchainGasPaymaster igp_) external onlyProtocolAdmin {

143:     function setChainId(uint64 superChainId_, uint32 ambChainId_) external onlyProtocolAdmin {

170:     function setReceiver(uint32 domain_, address authorizedImpl_) external onlyProtocolAdmin {

183:     function handle(uint32 origin_, bytes32 sender_, bytes calldata body_) external override onlyMailbox {
File: crosschain-data/adapters/layerzero/LayerzeroImplementation.sol

86:     function setLzEndpoint(address endpoint_) external onlyProtocolAdmin {

124:     function setSendVersion(uint16 version_) external override onlyProtocolAdmin {

129:     function setReceiveVersion(uint16 version_) external override onlyProtocolAdmin {

134:     function forceResumeReceive(uint16 srcChainId_, bytes calldata srcAddress_) external override onlyEmergencyAdmin {

139:     function setTrustedRemote(uint16 srcChainId_, bytes calldata srcAddress_) external onlyProtocolAdmin {

201:     function setChainId(uint64 superChainId_, uint16 ambChainId_) external onlyProtocolAdmin {
File: crosschain-data/adapters/wormhole/automatic-relayer/WormholeARImplementation.sol

76:     function setWormholeRelayer(address relayer_) external onlyProtocolAdmin {

198:     function setChainId(uint64 superChainId_, uint16 ambChainId_) external onlyProtocolAdmin {

225:     function setReceiver(uint16 chainId_, address authorizedImpl_) external onlyProtocolAdmin {
File: crosschain-data/adapters/wormhole/specialized-relayer/WormholeSRImplementation.sol

88:     function setWormholeCore(address wormhole_) external onlyProtocolAdmin {

98:     function setRelayer(address relayer_) external onlyProtocolAdmin {

106:     function setFinality(uint8 finality_) external onlyProtocolAdmin {

173:     function receiveMessage(bytes memory encodedMessage_) public onlyWormholeVAARelayer {

209:     function setChainId(uint64 superChainId_, uint16 ambChainId_) external onlyProtocolAdmin {

236:     function setReceiver(uint16 chainId_, address authorizedImpl_) external onlyProtocolAdmin {
File: payments/PayMaster.sol

51:     function withdrawTo(bytes32 superRegistryId_, uint256 nativeAmount_) external override onlyPaymentAdmin {

75:     function treatAMB(uint8 ambId_, uint256 nativeValue_, bytes memory data_) external override onlyPaymentAdmin {
File: settings/SuperRBAC.sol

138:     function setSuperRegistry(address superRegistry_) external override onlyRole(PROTOCOL_ADMIN_ROLE) {

147:     function setRoleAdmin(bytes32 role_, bytes32 adminRole_) external override onlyRole(PROTOCOL_ADMIN_ROLE) {

178:     function stateSyncBroadcast(bytes memory data_) external override onlyBroadcastRegistry {
File: settings/SuperRegistry.sol

207:     function setDelay(uint256 delay_) external override onlyProtocolAdmin {

219:     function setPermit2(address permit2_) external override onlyProtocolAdmin {

229:     function setVaultLimitPerTx(uint64 chainId_, uint256 vaultLimit_) external override onlyProtocolAdmin {

239:     function setAddress(bytes32 id_, address newAddress_, uint64 chainId_) external override onlyProtocolAdmin {

342:     function setRequiredMessagingQuorum(uint64 srcChainId_, uint256 quorum_) external override onlyProtocolAdmin {

[GAS-5] ++i costs less gas than i++, especially when it's used in for-loops (--i/i-- too)

Saves 5 gas per loop

Instances (1):

File: settings/SuperRBAC.sol

171:                 "SUPER_RBAC", SYNC_REVOKE, abi.encode(++xChainPayloadCounter, role_, superRegistryAddressId_)

[GAS-6] Using private rather than public for constants, saves gas

If needed, the values can be read from the verified contract source code, or if there are multiple values there can be a single getter function that returns a tuple of the values of all currently-public constants. 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

Instances (34):

File: settings/SuperRBAC.sol

13:     bytes32 public constant SYNC_REVOKE = keccak256("SYNC_REVOKE");

17:     bytes32 public constant override PROTOCOL_ADMIN_ROLE = keccak256("PROTOCOL_ADMIN_ROLE");

21:     bytes32 public constant override EMERGENCY_ADMIN_ROLE = keccak256("EMERGENCY_ADMIN_ROLE");

25:     bytes32 public constant override PAYMENT_ADMIN_ROLE = keccak256("PAYMENT_ADMIN_ROLE");

30:     bytes32 public constant override BROADCASTER_ROLE = keccak256("BROADCASTER_ROLE");

34:     bytes32 public constant override CORE_STATE_REGISTRY_PROCESSOR_ROLE =

39:     bytes32 public constant override TIMELOCK_STATE_REGISTRY_PROCESSOR_ROLE =

44:     bytes32 public constant override BROADCAST_STATE_REGISTRY_PROCESSOR_ROLE =

49:     bytes32 public constant override CORE_STATE_REGISTRY_UPDATER_ROLE = keccak256("CORE_STATE_REGISTRY_UPDATER_ROLE");

53:     bytes32 public constant override CORE_STATE_REGISTRY_RESCUER_ROLE = keccak256("CORE_STATE_REGISTRY_RESCUER_ROLE");

57:     bytes32 public constant override CORE_STATE_REGISTRY_DISPUTER_ROLE = keccak256("CORE_STATE_REGISTRY_DISPUTER_ROLE");

61:     bytes32 public constant override DST_SWAPPER_ROLE = keccak256("DST_SWAPPER_ROLE");

66:     bytes32 public constant override WORMHOLE_VAA_RELAYER_ROLE = keccak256("WORMHOLE_VAA_RELAYER_ROLE");
File: settings/SuperRegistry.sol

20:     bytes32 public constant override SUPERFORM_ROUTER = keccak256("SUPERFORM_ROUTER");

23:     bytes32 public constant override SUPERFORM_FACTORY = keccak256("SUPERFORM_FACTORY");

26:     bytes32 public constant override SUPER_TRANSMUTER = keccak256("SUPER_TRANSMUTER");

29:     bytes32 public constant override PAYMASTER = keccak256("PAYMASTER");

33:     bytes32 public constant override PAYMENT_HELPER = keccak256("PAYMENT_HELPER");

36:     bytes32 public constant override CORE_STATE_REGISTRY = keccak256("CORE_STATE_REGISTRY");

39:     bytes32 public constant override TIMELOCK_STATE_REGISTRY = keccak256("TIMELOCK_STATE_REGISTRY");

42:     bytes32 public constant override BROADCAST_REGISTRY = keccak256("BROADCAST_REGISTRY");

45:     bytes32 public constant override SUPER_POSITIONS = keccak256("SUPER_POSITIONS");

48:     bytes32 public constant override SUPER_RBAC = keccak256("SUPER_RBAC");

51:     bytes32 public constant override PAYLOAD_HELPER = keccak256("PAYLOAD_HELPER");

54:     bytes32 public constant override DST_SWAPPER = keccak256("DST_SWAPPER");

57:     bytes32 public constant override EMERGENCY_QUEUE = keccak256("EMERGENCY_QUEUE");

60:     bytes32 public constant override PAYMENT_ADMIN = keccak256("PAYMENT_ADMIN");

61:     bytes32 public constant override CORE_REGISTRY_PROCESSOR = keccak256("CORE_REGISTRY_PROCESSOR");

62:     bytes32 public constant override BROADCAST_REGISTRY_PROCESSOR = keccak256("BROADCAST_REGISTRY_PROCESSOR");

63:     bytes32 public constant override TIMELOCK_REGISTRY_PROCESSOR = keccak256("TIMELOCK_REGISTRY_PROCESSOR");

64:     bytes32 public constant override CORE_REGISTRY_UPDATER = keccak256("CORE_REGISTRY_UPDATER");

65:     bytes32 public constant override CORE_REGISTRY_RESCUER = keccak256("CORE_REGISTRY_RESCUER");

66:     bytes32 public constant override CORE_REGISTRY_DISPUTER = keccak256("CORE_REGISTRY_DISPUTER");

67:     bytes32 public constant override DST_SWAPPER_PROCESSOR = keccak256("DST_SWAPPER_PROCESSOR");

Low Issues

Issue Instances
L-1 Empty Function Body - Consider commenting why 14
L-2 Initializers could be front-run 3

[L-1] Empty Function Body - Consider commenting why

Instances (14):

File: BaseForm.sol

149:     receive() external payable { }
File: BaseRouter.sol

40:     receive() external payable { }
File: BaseRouterImplementation.sol

82:     constructor(address superRegistry_) BaseRouter(superRegistry_) { }
File: SuperformRouter.sol

13:     constructor(address superRegistry_) BaseRouterImplementation(superRegistry_) { }
File: crosschain-data/extensions/TimelockStateRegistry.sol

63:     constructor(ISuperRegistry superRegistry_) BaseStateRegistry(superRegistry_) { }

156:         try form.withdrawAfterCoolDown(p) { }
File: crosschain-liquidity/DstSwapper.sol

114:     receive() external payable { }
File: crosschain-liquidity/lifi/LiFiValidator.sol

14:     constructor(address superRegistry_) BridgeValidator(superRegistry_) { }
File: crosschain-liquidity/socket/SocketOneInchValidator.sol

12:     constructor(address superRegistry_) BridgeValidator(superRegistry_) { }
File: crosschain-liquidity/socket/SocketValidator.sol

12:     constructor(address superRegistry_) BridgeValidator(superRegistry_) { }
File: forms/ERC4626Form.sol

18:     constructor(address superRegistry_) ERC4626FormImplementation(superRegistry_, stateRegistryId) { }
File: forms/ERC4626KYCDaoForm.sol

17:     constructor(address superRegistry_) ERC4626FormImplementation(superRegistry_, stateRegistryId) { }
File: forms/ERC4626TimelockForm.sol

45:     constructor(address superRegistry_) ERC4626FormImplementation(superRegistry_, stateRegistryId) { }
File: payments/PayMaster.sol

48:     receive() external payable { }

[L-2] Initializers could be front-run

Initializers could be front-run, allowing an attacker to either set their own values, take ownership of the contract, and in the best case forcing a re-deployment

Instances (3):

File: BaseForm.sol

154:     function initialize(address superRegistry_, address vault_, address asset_) external initializer {

154:     function initialize(address superRegistry_, address vault_, address asset_) external initializer {
File: SuperformFactory.sol

207:         BaseForm(payable(superform_)).initialize(address(superRegistry), vault_, address(IERC4626(vault_).asset()));

Medium Issues

Issue Instances
M-1 Centralization Risk for trusted owners 4

[M-1] Centralization Risk for trusted owners

Impact:

Contracts have owners with privileged rights to perform admin tasks and need to be trusted to not perform malicious updates or drain funds.

Instances (4):

File: settings/SuperRBAC.sol

8: contract SuperRBAC is ISuperRBAC, AccessControlEnumerable {

138:     function setSuperRegistry(address superRegistry_) external override onlyRole(PROTOCOL_ADMIN_ROLE) {

147:     function setRoleAdmin(bytes32 role_, bytes32 adminRole_) external override onlyRole(PROTOCOL_ADMIN_ROLE) {

160:         onlyRole(PROTOCOL_ADMIN_ROLE)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment