Omniscia CloudFunding Audit

Manager Code Style Findings

Manager Code Style Findings

MAN-01C: Expensive Array Maintenance Operation

Description:

The ftsoRewardManagersTmp array is a temporary array that retains the managers that should be added after they are all identified as they need to be included in reverse order.

Example:

contracts/Manager.sol
50function updateFtsoRewardManagers() external {
51 IFtsoRewardManager lastSaved = ftsoRewardManagers[ftsoRewardManagers.length - 1];
52 IFtsoRewardManager current = FlareLibrary.getFtsoRewardManager(FlareLibrary.getFtsoManager());
53 if (current != lastSaved) {
54 do {
55 ftsoRewardManagersTmp.push(current);
56 IFtsoRewardManager previous = getPreviousFtsoRewardManager(current);
57 if (previous == lastSaved || address(previous) == address(0)) break;
58 current = previous;
59 } while (true);
60 for (uint256 i = ftsoRewardManagersTmp.length; i > 0; i--) {
61 IFtsoRewardManager ftsoRewardManager = ftsoRewardManagersTmp[i - 1];
62 ftsoRewardManagers.push(ftsoRewardManager);
63 ftsoRewardManagersTmp.pop();
64 emit AddFtsoRewardManager(address(ftsoRewardManager));
65 }
66 }
67}

Recommendation:

We advise the updateFtsoRewardManagers function to introduce an input argument specifying the number of expected managers to add in the loop and an in-memory dynamic array to be created instead, removing the need for a very expensive storage array and optimizing the gas cost of the function significantly.

Alleviation:

The CloudFunding team has opted not to alleviate any informational or minor exhibits they disagree with, thus rendering this exhibit as acknowledged.

MAN-02C: Suboptimal Iteration of Potential New Managers

Description:

The getFtsoRewardManagers function currently contains additional logic handling up to 3 new reward managers, however, this is redundant as the updateFtsoRewardManagers could be invoked instead.

Example:

contracts/Manager.sol
69function getFtsoRewardManagers() external view returns (IFtsoRewardManager[] memory managers) {
70 IFtsoRewardManager lastSaved = ftsoRewardManagers[ftsoRewardManagers.length - 1];
71 IFtsoRewardManager current = FlareLibrary.getFtsoRewardManager(FlareLibrary.getFtsoManager());
72 if (current == lastSaved) {
73 // no changes
74 managers = ftsoRewardManagers;
75 } else {
76 // new ftso reward manager(s), handle up to 2 new
77 IFtsoRewardManager[] memory extra = new IFtsoRewardManager[](3);
78 uint256 count;
79 extra[count] = current;
80 do {
81 count++;
82 require(count < extra.length, 'Update FtsoRewardManager');
83 extra[count] = getPreviousFtsoRewardManager(extra[count - 1]);
84 } while (extra[count] != lastSaved && address(extra[count]) != address(0));
85 uint256 previousLen = ftsoRewardManagers.length;
86 managers = new IFtsoRewardManager[](previousLen + count);
87 for (uint256 i; i < previousLen; i++) {
88 managers[i] = ftsoRewardManagers[i];
89 }
90 for (uint256 i; i < count; i++) {
91 managers[previousLen + i] = extra[count - i - 1];
92 }
93 }
94}

Recommendation:

We advise the updateFtsoRewardManagers function to be invoked in an if (current != lastSaved) block and ftsoRewardManagers to always be yielded by the function. This will work well with the secondary optimization exhibit outlined previously as it would allow the call to be made with an argument of 3 being identical to the current implementation's logic.

Alleviation:

The CloudFunding team has opted not to alleviate any informational or minor exhibits they disagree with, thus rendering this exhibit as acknowledged.