Omniscia Mean Finance Audit

TransformerRegistry Manual Review Findings

TransformerRegistry Manual Review Findings

TRY-01M: Inexistent Deprecation Workflow

Description:

The registerTransformers function & removeTransformers function permit previously registered transformers to be arbitrarily overwritten.

Example:

solidity/contracts/TransformerRegistry.sol
22/// @inheritdoc ITransformerRegistry
23function registerTransformers(TransformerRegistration[] calldata _registrations) external onlyGovernor {
24 for (uint256 i; i < _registrations.length; i++) {
25 TransformerRegistration memory _registration = _registrations[i];
26 // Make sure the given address is actually a transformer
27 bool _isTransformer = ERC165Checker.supportsInterface(_registration.transformer, type(ITransformer).interfaceId);
28 if (!_isTransformer) revert AddressIsNotTransformer(_registration.transformer);
29 for (uint256 j; j < _registration.dependents.length; j++) {
30 _registeredTransformer[_registration.dependents[j]] = ITransformer(_registration.transformer);
31 }
32 }
33 emit TransformersRegistered(_registrations);
34}

Recommendation:

We advise some form of deprecation methodology to be utilized instead ensuring that the transformers cannot be maliciously adjusted at will as otherwise the registerTransformers & removeTransformers functions pose a significant centralization risk.

Alleviation (6ed56b5449ca241fc6be369d44f392f1f5313f93):

The Mean Finance team evaluated this exhibit but opted not to apply a remediation for it in the current version of the codebase as they deem it a non-issue. As a result, we consider the exhibit acknowledged.

TRY-02M: Incorrect Balance Measurement Methodology

Description:

The transformAllToDependent function incorrectly measures the balance available for the transformToDependent call for any native asset as it does not utilize the current address(this).balance.

Impact:

The transformAllToDependent function is currently inoperable for any transformer using native assets as the balanceOf measurement will fail at the designated PROTOCOL_TOKEN address.

Example:

solidity/contracts/TransformerRegistry.sol
125/// @inheritdoc ITransformerRegistry
126function transformAllToDependent(address _dependent, address _recipient) external payable returns (uint256) {
127 ITransformer _transformer = _getTransformerOrFail(_dependent);
128
129 // Calculate underlying
130 address[] memory _underlying = _transformer.getUnderlying(_dependent);
131 UnderlyingAmount[] memory _underlyingAmount = new UnderlyingAmount[](_underlying.length);
132 for (uint256 i; i < _underlying.length; i++) {
133 address _underlyingToken = _underlying[i];
134 _underlyingAmount[i] = UnderlyingAmount({underlying: _underlyingToken, amount: IERC20(_underlyingToken).balanceOf(msg.sender)});
135 }
136
137 // Delegate
138 bytes memory _result = _delegateToTransformer(
139 _transformer,
140 abi.encodeWithSelector(_transformer.transformToDependent.selector, _dependent, _underlyingAmount, _recipient)
141 );
142 return abi.decode(_result, (uint256));
143}

Recommendation:

We advise the case of the PROTOCOL_TOKEN to be handled appropriately by including a conditional that instead uses address(this).balance (which accounts for the currently active msg.value) for the UnderlyingAmount entry that will ultimately be transmitted to the transformer.

Alleviation (6ed56b5449ca241fc6be369d44f392f1f5313f93):

The balance measurement methodology was adequately updated to branch depending on whether the _underlyingToken represents the PROTOCOL_TOKEN or not, ensuring that the balances are measured correctly.