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 relevant chain that gets reviewed and its corresponding software repository. The document explaining these questions is here.
1. Are the smart contract addresses easy to find? (%)
dYdX's smart contract addresses can be found in their solo - migrations repository under deployed.json. A screenshot of the smart contract addresses can be found in the appendix below.
2. How active is the primary contract? (%)
The protocol's SoloMargin.sol contract is active with more than 10 transactions a week, but not more than 10 transactions a day, which results in a 70% score. A screenshot of last months transactions can be found in the appendix.
3. Does the protocol have a public software repository? (Y/N)
Their GitHub repository can be found here.
4. Is there a development history visible? (%)
dydx's solo repository has recorded 501 commits and 2 branches, earning them a 100%.
5. Is the team public (not anonymous)?
The team is public and can be found on their LinkedIn page.
This section looks at the software documentation. The document explaining these questions is here.
6. Is there a whitepaper? (Y/N)
dydx's README.md provides documentation on the protocol as well as their docs.dydx.exchange link.
7. Is the protocol's software architecture documented? (Y/N)
This protocol's software architecture is documented in their formal documentation through written explanations.
8. Does the software documentation fully cover the deployed contracts' source code? (%)
dydx's solo contracts repo provides the function of each smart contract. Documentation is also linked.
9. Is it possible to trace the documented software to its implementation in the protocol's source code? (%)
The protocol explicitly links the smart contract functions to its representative source code, which rewards dydx with a 100%.
10. Has the protocol tested their deployed code? (%)
dYdX has a strong TtC ratio of 222%, earning the protocol a 100% score. An appendix entry can be found on the testing factors.
11. How covered is the protocol's code? (%)
dydx has 100% of line and branch coverage.
12. Does the protocol provide scripts and instructions to run their tests? (Y/N)
Scripts/Instructions location: https://github.com/dydxprotocol/solo#test
13. Is there a detailed report of the protocol's test results?(%)
The protocol's GitHub code coverage report can be found here
14. Has the protocol undergone Formal Verification? (Y/N)
dydx has not shown evidence of undergoing Formal Verification.
15. Were the smart contracts deployed to a testnet? (Y/N)
Testnet documentation can be found here and the testnet used is Ropsten.
This section looks at the 3rd party software audits done. It is explained in this document.
16. Is the protocol sufficiently audited? (%)
dydx has 2 audits that were made pre-launch alongside additional Layer 2 audit. Pre-launch audits can be found here.
17. Is the bounty value acceptably high (%)
dydx has an active bug bounty of 50 000$ found on Immunefi
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.
18. Is the protocol's admin control information easy to find?
There is a clear Governance strapiuct (proposals and forums) for dydx as well as governance documentation related to how the protocol works out.
19. Are relevant contracts clearly labelled as upgradeable or immutable? (%)
All contracts are labelled as upgradeable in the Voting & Governance repository under governance parameters
20. Is the type of smart contract ownership clearly indicated? (%)
Ownership is indicated as MultiSig in the 4_ownership.js files in the code.
21. Are the protocol's smart contract change capabilities described? (%)
Smart contract change capabilities are clearly identified in the Voting & Governance repository.
22. Is the protocol's admin control information easy to understand? (%)
The information available on governance is not in software-specific language; the information is easy to understand.
23. Is there sufficient Pause Control documentation? (%)
dydx has a function similar to Pause controls called Pauser/Unpauser role, which allows to pause updates to the merkle root through a timelock. There are however no further detail or testing done on the function.
24. Is there sufficient Timelock documentation? (%)
dydx documents their timelock parameters here.
25. Is the Timelock of an adequate length? (Y/N)
Different timelock durations are applied depending on the functions executed, ranging from 1 day to 21 days. A detailed table of the timelock parameters can be found here.
This section goes over the documentation that a protocol may or may not supply about their Oracle usage. Oracles are a fundamental part of DeFi as they are responsible for relaying tons of price data information to thousands of protocols using blockchain technology. Not only are they important for price feeds, but they are also an essential component of transaction verification and security. These questions are explained in this document.
26. Is the protocol's Oracle sufficiently documented? (%)
27. Is front running mitigated by this protocol? (Y/N)
dydx documents front running mitigation in their documentation. In fact, they move to an entirely new network for it.
28. Can flashloan attacks be applied to the protocol, and if so, are those flashloan attack risks mitigated? (Y/N)
While the Guardian role has functions related to "restrict[ing] open actions with borrowed funds", there are no clear flashloan attack mitigation techniques documented. In addition, flashloans are critical to the operation of dYdX so they would not seek to prevent flashloan usage by their userbase. As such, we will award points.
1/*
2 Copyright 2019 dYdX Trading Inc.
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 http://www.apache.org/licenses/LICENSE-2.0
7 Unless required by applicable law or agreed to in writing, software
8 distributed under the License is distributed on an "AS IS" BASIS,
9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 See the License for the specific language governing permissions and
11 limitations under the License.
12*/
13
14pragma solidity 0.5.7;
15pragma experimental ABIEncoderV2;
16
17import { MultiSig } from "./MultiSig.sol";
18
19
20/**
21 * @title DelayedMultiSig
22 * @author dYdX
23 *
24 * Multi-Signature Wallet with delay in execution.
25 * Allows multiple parties to execute a transaction after a time lock has passed.
26 * Adapted from Amir Bandeali's MultiSigWalletWithTimeLock contract.
27 * Logic Changes:
28 * - Only owners can execute transactions
29 * - Require that each transaction succeeds
30 * - Added function to execute multiple transactions within the same Ethereum transaction
31 */
32contract DelayedMultiSig is
33 MultiSig
34{
35 // ============ Events ============
36
37 event ConfirmationTimeSet(uint256 indexed transactionId, uint256 confirmationTime);
38 event TimeLockChange(uint32 secondsTimeLocked);
39
40 // ============ Storage ============
41
42 uint32 public secondsTimeLocked;
43 mapping (uint256 => uint256) public confirmationTimes;
44
45 // ============ Modifiers ============
46
47 modifier notFullyConfirmed(
48 uint256 transactionId
49 ) {
50 require(
51 !isConfirmed(transactionId),
52 "TX_FULLY_CONFIRMED"
53 );
54 _;
55 }
56
57 modifier fullyConfirmed(
58 uint256 transactionId
59 ) {
60 require(
61 isConfirmed(transactionId),
62 "TX_NOT_FULLY_CONFIRMED"
63 );
64 _;
65 }
66
67 modifier pastTimeLock(
68 uint256 transactionId
69 ) {
70 require(
71 block.timestamp >= confirmationTimes[transactionId] + secondsTimeLocked,
72 "TIME_LOCK_INCOMPLETE"
73 );
74 _;
75 }
76
77 // ============ Constructor ============
78
79 /**
80 * Contract constructor sets initial owners, required number of confirmations, and time lock.
81 *
82 * @param _owners List of initial owners.
83 * @param _required Number of required confirmations.
84 * @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it
85 * becomes executable, in seconds.
86 */
87 constructor (
88 address[] memory _owners,
89 uint256 _required,
90 uint32 _secondsTimeLocked
91 )
92 public
93 MultiSig(_owners, _required)
94 {
95 secondsTimeLocked = _secondsTimeLocked;
96 }
97
98 // ============ Wallet-Only Functions ============
99
100 /**
101 * Changes the duration of the time lock for transactions.
102 *
103 * @param _secondsTimeLocked Duration needed after a transaction is confirmed and before it
104 * becomes executable, in seconds.
105 */
106 function changeTimeLock(
107 uint32 _secondsTimeLocked
108 )
109 public
110 onlyWallet
111 {
112 secondsTimeLocked = _secondsTimeLocked;
113 emit TimeLockChange(_secondsTimeLocked);
114 }
115
116 // ============ Admin Functions ============
117
118 /**
119 * Allows an owner to confirm a transaction.
120 * Overrides the function in MultiSig.
121 *
122 * @param transactionId Transaction ID.
123 */
124 function confirmTransaction(
125 uint256 transactionId
126 )
127 public
128 ownerExists(msg.sender)
129 transactionExists(transactionId)
130 notConfirmed(transactionId, msg.sender)
131 notFullyConfirmed(transactionId)
132 {
133 confirmations[transactionId][msg.sender] = true;
134 emit Confirmation(msg.sender, transactionId);
135 if (isConfirmed(transactionId)) {
136 setConfirmationTime(transactionId, block.timestamp);
137 }
138 }
139
140 /**
141 * Allows an owner to execute a confirmed transaction.
142 * Overrides the function in MultiSig.
143 *
144 * @param transactionId Transaction ID.
145 */
146 function executeTransaction(
147 uint256 transactionId
148 )
149 public
150 ownerExists(msg.sender)
151 notExecuted(transactionId)
152 fullyConfirmed(transactionId)
153 pastTimeLock(transactionId)
154 {
155 Transaction storage txn = transactions[transactionId];
156 txn.executed = true;
157 bool success = externalCall(
158 txn.destination,
159 txn.value,
160 txn.data.length,
161 txn.data
162 );
163 require(
164 success,
165 "TX_REVERTED"
166 );
167 emit Execution(transactionId);
168 }
169
170 /**
171 * Allows an owner to execute multiple confirmed transactions.
172 *
173 * @param transactionIds List of transaction IDs.
174 */
175 function executeMultipleTransactions(
176 uint256[] memory transactionIds
177 )
178 public
179 ownerExists(msg.sender)
180 {
181 for (uint256 i = 0; i < transactionIds.length; i++) {
182 executeTransaction(transactionIds[i]);
183 }
184 }
185
186 // ============ Helper Functions ============
187
188 /**
189 * Sets the time of when a submission first passed.
190 */
191 function setConfirmationTime(
192 uint256 transactionId,
193 uint256 confirmationTime
194 )
195 internal
196 {
197 confirmationTimes[transactionId] = confirmationTime;
198 emit ConfirmationTimeSet(transactionId, confirmationTime);
199 }
200}
Tests to Code: 19961 / 9008 = 222 %