If you notice some outdated information please let us know!
PASS
The final review score is indicated as a percentage. The percentage is calculated as Achieved Points due to MAX Possible Points. For each element the answer can be either Yes/No or a percentage. For a detailed breakdown of the individual weights of each question, please consult this document.
Very simply, the audit looks for the following declarations from the developer's site. With these declarations, it is reasonable to trust the smart contracts.
This report is for informational purposes only and does not constitute investment advice of any kind, nor does it constitute an offer to provide investment advisory or other services. Nothing in this report shall be considered a solicitation or offer to buy or sell any security, token, future, option or other financial instrument or to offer or provide any investment advice or service to any person in any jurisdiction. Nothing contained in this report constitutes investment advice or offers any opinion with respect to the suitability of any security, and the views expressed in this report should not be taken as advice to buy, sell or hold any security. The information in this report should not be relied upon for the purpose of investing. In preparing the information contained in this report, we have not taken into account the investment needs, objectives and financial circumstances of any particular investor. This information has no regard to the specific investment objectives, financial situation and particular needs of any specific recipient of this information and investments discussed may not be suitable for all investors.
Any views expressed in this report by us were prepared based upon the information available to us at the time such views were written. The views expressed within this report are limited to DeFiSafety and the author and do not reflect those of any additional or third party and are strictly based upon DeFiSafety, its authors, interpretations and evaluation of relevant data. Changed or additional information could cause such views to change. All information is subject to possible correction. Information may quickly become unreliable for various reasons, including changes in market conditions or economic circumstances.
This completed report is copyright (c) DeFiSafety 2023. Permission is given to copy in whole, retaining this copyright label.
This section looks at the code deployed on the Mainnet that gets reviewed and its corresponding software repository. The document explaining these questions is here.
1. Are the executing code addresses readily available? (%)
They are available at website https://docs.loopring.io/en/basics/contracts.html , as indicated in the /Appendix.
2. Is the code actively being used? (%)
Activity is 20 transactions a day on contract ExchangeV3, as indicated in the Appendix.
3. Is there a public software repository? (Y/N)
GitHub: https://github.com/Loopring
Is there a public software repository with the code at a minimum, but also normally test and scripts. Even if the repository was created just to hold the files and has just 1 transaction, it gets a "Yes". For teams with private repositories, this answer is "No"
4. Is there a development history visible? (%)
At 15 branches and 3,491 commits, it's entirely possible Loopring themselves are looking into a layer 2 solution for navigating their bountiful development history.
This metric checks if the software repository demonstrates a strong steady history. This is normally demonstrated by commits, branches and releases in a software repository. A healthy history demonstrates a history of more than a month (at a minimum).
5. Is the team public (not anonymous)? (Y/N)
For a "Yes" in this question, the real names of some team members must be public on the website or other documentation (LinkedIn, etc). If the team is anonymous, then this question is a "No".
This section looks at the software documentation. The document explaining these questions is here.
6. Is there a whitepaper? (Y/N)
7. Are the basic software functions documented? (Y/N)
The basic software functions are covered in the documentation. Loopring's living, breathing design document is a robust way to organize such documentation and should be commended for the considerable effort put in.
8. Does the software function documentation fully (100%) cover the deployed contracts? (%)
Contracts as varied as minting NFTs on Loopring's network and on-chain signatures to simple deposits are covered by this document. There is also in-depth software documentation at https://github.com/Loopring/protocols/blob/master/packages/loopring_v3/circuit/statements.md, as well as API documentation at https://docs.loopring.io/en/REST_APIS.html.
9. Are there sufficiently detailed comments for all functions within the deployed contract code (%)
The Comments to Code (CtC) ratio is the primary metric for this score.
10. Is it possible to trace from software documentation to the implementation in code (%)
There is clear association between the code and the documentation, though it is lacking explicit traceability.
11. Full test suite (Covers all the deployed code) (%)
This score is guided by the Test to Code ratio (TtC). Generally a good test to code ratio is over 100%. However the reviewers best judgement is the final deciding factor.
12. Code coverage (Covers all the deployed lines of code, or explains misses) (%)
The most recent published code coverage test was from 2017, making this not applicable to V3. Nevertheless, at an astonishing 18,000 lines of test code, it is clear that significant testing has been conducted.
13. Scripts and instructions to run the tests? (Y/N)
Scripts/Instructions location: https://github.com/Loopring/protocols/tree/master/packages/loopring_v3#run-unit-tests
14. Report of the results (%)
No test dissertation was located.
15. Formal Verification test done (%)
Loopring V2 underwent formal verification, but V3 has not yet.
This section looks at the 3rd party software audits done. It is explained in this document.
17. Did 3rd Party audits take place? (%)
18. Is the bug bounty acceptable high? (%)
Loopring had a 3 month bug bounty period that has now expired, meaning there is no bug bounty currently offered. The value of the aforementioned Bug Bounty was around 300k for the most critical of bu finds.
This section covers the documentation of special access controls for a DeFi protocol. The admin access controls are the contracts that allow updating contracts or coefficients in the protocol. Since these contracts can allow the protocol admins to "change the rules", complete disclosure of capabilities is vital for user's transparency. It is explained in this document.
19. Can a user clearly and quickly find the status of the access controls (%)
Admin control information was found at the bottom of the Loopring website. You can view it at https://loopring.io/#/document/risks_en.md.
20. Is the information clear and complete (%)
21. Is the information in non-technical terms that pertain to the investments (%)
The admin control documentation is written in clear language that relates to the users' investment safety. It can be found at https://loopring.io/#/document/risks_en.md.
22. Is there Pause Control documentation including records of tests (%)
A "withdrawal mode" is detailed, and it operates as a pause control function for the AMM. The last test was performed around 2 months ago at https://github.com/Loopring/protocols/blob/master/packages/loopring_v3/test/testExchangeWithdrawalMode.ts.
1/ SPDX-License-Identifier: Apache-2.0
2/ Copyright 2017 Loopring Technology Limited.
3pragma solidity ^0.7.0;
4pragma experimental ABIEncoderV2;
5
6import "../aux/access/ITransactionReceiver.sol";
7import "../core/iface/IAgentRegistry.sol";
8import "../lib/ReentrancyGuard.sol";
9import "../lib/TransferUtil.sol";
10import "./libamm/AmmAssetManagement.sol";
11import "./libamm/AmmData.sol";
12import "./libamm/AmmExitRequest.sol";
13import "./libamm/AmmJoinRequest.sol";
14import "./libamm/AmmPoolToken.sol";
15import "./libamm/AmmStatus.sol";
16import "./libamm/AmmTransactionReceiver.sol";
17import "./libamm/AmmWithdrawal.sol";
18import "./PoolToken.sol";
19
20
21/// @title LoopringAmmPool
22contract LoopringAmmPool is
23 PoolToken,
24 IAgent,
25 ITransactionReceiver,
26 ReentrancyGuard
27{
28 using AmmAssetManagement for AmmData.State;
29 using AmmJoinRequest for AmmData.State;
30 using AmmExitRequest for AmmData.State;
31 using AmmPoolToken for AmmData.State;
32 using AmmStatus for AmmData.State;
33 using AmmTransactionReceiver for AmmData.State;
34 using AmmWithdrawal for AmmData.State;
35 using TransferUtil for address;
36
37 event PoolJoinRequested(AmmData.PoolJoin join);
38 event PoolExitRequested(AmmData.PoolExit exit, bool force);
39 event ForcedExitProcessed(address owner, uint96 burnAmount, uint96[] amounts);
40 event Shutdown(uint timestamp);
41
42 IAmmController public immutable controller;
43 IAssetManager public immutable assetManager;
44 bool public immutable joinsDisabled;
45
46 modifier onlyFromExchangeOwner()
47 {
48 require(msg.sender == state.exchangeOwner, "UNAUTHORIZED");
49 _;
50 }
51
52 modifier onlyFromAssetManager()
53 {
54 require(msg.sender == address(assetManager), "UNAUTHORIZED");
55 _;
56 }
57
58 modifier onlyFromController()
59 {
60 require(msg.sender == address(controller), "UNAUTHORIZED");
61 _;
62 }
63
64 modifier onlyWhenOnline()
65 {
66 require(state.isOnline(), "NOT_ONLINE");
67 _;
68 }
69
70 modifier onlyWhenOffline()
71 {
72 require(!state.isOnline(), "NOT_OFFLINE");
73 _;
74 }
75
76 constructor(
77 IAmmController _controller,
78 IAssetManager _assetManager,
79 bool _joinsDisabled
80 )
81 {
82 require(_controller != IAmmController(0), "ZERO_ADDRESS");
83 controller = _controller;
84 assetManager = _assetManager;
85 joinsDisabled = _joinsDisabled;
86 }
87
88 function isOnline()
89 public
90 view
91 returns (bool)
92 {
93 return state.isOnline();
94 }
95
96 receive() payable external {}
97
98 function setupPool(AmmData.PoolConfig calldata config)
99 external
100 nonReentrant
101 {
102 require(state.accountID == 0 || msg.sender == address(controller), "UNAUTHORIZED");
103 state.setupPool(config);
104 }
105
106 function enterExitMode(bool enabled)
107 external
108 onlyFromController
109 {
110 require(state.exitMode != enabled, "INVALID_STATE");
111 state.exitMode = enabled;
112 }
113
114 // Anyone is able to shut down the pool when requests aren't being processed any more.
115 function shutdown(address exitOwner)
116 external
117 payable
118 onlyWhenOnline
119 nonReentrant
120 {
121 state.shutdownByLP(exitOwner);
122 }
123
124 function shutdownByController()
125 external
126 onlyWhenOnline
127 nonReentrant
128 onlyFromController
129 {
130 state.shutdownByController();
131 }
132
133 function joinPool(
134 uint96[] calldata joinAmounts,
135 uint96 mintMinAmount,
136 uint96 fee
137 )
138 external
139 payable
140 onlyWhenOnline
141 nonReentrant
142 {
143 state.joinPool(joinAmounts, mintMinAmount, fee);
144 }
145
146 function exitPool(
147 uint96 burnAmount,
148 uint96[] calldata exitMinAmounts
149 )
150 external
151 payable
152 onlyWhenOnline
153 nonReentrant
154 {
155 state.exitPool(burnAmount, exitMinAmounts, false);
156 }
157
158 function forceExitPool(
159 uint96 burnAmount,
160 uint96[] calldata exitMinAmounts
161 )
162 external
163 payable
164 onlyWhenOnline
165 nonReentrant
166 {
167 state.exitPool(burnAmount, exitMinAmounts, true);
168 }
169
170 function onReceiveTransactions(
171 bytes calldata txsData,
172 bytes calldata callbackData
173 )
174 external
175 override
176 onlyWhenOnline
177 onlyFromExchangeOwner
178 // nonReentrant // Not needed, does not do any external calls
179 // and can only be called by the exchange owner.
180 {
181 AmmData.Settings memory settings = AmmData.Settings({
182 controller: controller,
183 assetManager: assetManager,
184 joinsDisabled: joinsDisabled
185 });
186 state.onReceiveTransactions(txsData, callbackData, settings);
187 }
188
189 function withdrawWhenOffline()
190 external
191 onlyWhenOffline
192 nonReentrant
193 {
194 state.withdrawWhenOffline();
195 }
196
197 function transferOut(
198 address to,
199 address token,
200 uint amount
201 )
202 external
203 nonReentrant
204 onlyFromAssetManager
205 {
206 state.transferOut(to, token, amount);
207 }
208
209 function setBalanceL1(
210 address token,
211 uint96 balance
212 )
213 external
214 nonReentrant
215 onlyFromAssetManager
216 {
217 state.balancesL1[token] = balance;
218 }
219
220 function getBalanceL1(
221 address token
222 )
223 public
224 view
225 returns (uint96)
226 {
227 return state.balancesL1[token];
228 }
229}
Comments to Code: 783 / 3120 = 25 %
Tests to Code: 18912 / 3120 = 606 %