If you notice some outdated information please let us know!
FAIL
Hop comes close to our arbitrary passing grade thanks to good process quality. Good documentation (though brief) and a clear team structure alongside great audit practises are the strengths of Hop. However, it should implement a bug bounty as well as explain their testing methodologies a little more clearly. Most critical to improve however is clear information relating to access controls: there is no information about this. All things considered though, they document their development processes relatively robustly.
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? (%)
They can be found at https://github.com/hop-protocol/hop/blob/develop/packages/core/src/addresses/mainnet.ts, as indicated in the Appendix.
2. How active is the primary contract? (%)
Contract Optimism Token Bridge is used 10+ times a day, as indicated in the Appendix.
3. Does the protocol have a public software repository? (Y/N)
Hop uses GitHub.
4. Is there a development history visible? (%)
At 959 commits, this protocol's commitment to development is evidently a hop to perfection.
5. Is the team public (not anonymous)?
Two public team members were found on LinkedIn. This is documented in the appendix.
This section looks at the software documentation. The document explaining these questions is here.
6. Is there a whitepaper? (Y/N)
Location: https://docs.hop.exchange/
7. Is the protocol's software architecture documented? (Y/N)
Hop's software architecture is documented in full in the GitHub repo.
8. Does the software documentation fully cover the deployed contracts' source code? (%)
There is some coverage of deployed contracts by software function documentation. Individual functions are identified and the analysis is a high-level overview.
9. Is it possible to trace the documented software to its implementation in the protocol's source code? (%)
There is perfect traceability between software documentation and implemented code.
10. Has the protocol tested their deployed code? (%)
Code examples are in the Appendix at the end of this report.. As per the SLOC, there is 1121% testing to code (TtC). This score is guided by the Test to Code ratio (TtC). Generally a good test to code ratio is over 100%. This protocol has a remarkable 10 lines of test code in solidity / typescript for each line of deployed solidity.
11. How covered is the protocol's code? (%)
There is no test for code coverage documented, though it is clear this protocol has undergone massive testing. Given the 10x code ratio, it is obvious that all lines of code are covered.
12. Does the protocol provide scripts and instructions to run their tests? (Y/N)
Test scripts can be found here.
13. Is there a detailed report of the protocol's test results?(%)
There is no test report evident.
14. Has the protocol undergone Formal Verification? (Y/N)
This protocol has not undergone formal verification.
15. Were the smart contracts deployed to a testnet? (Y/N)
Hop documents its deployment to a testnet by providing these contracts. Users can verify them.
This section looks at the 3rd party software audits done. It is explained in this document.
16. Is the protocol sufficiently audited? (%)
Hop was audited twice before launch.
17. Is the bounty value acceptably high (%)
No information relating to a bug bounty was found in Hop's documentation.
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?
Admin control information was not documented by Hop.
19. Are relevant contracts clearly labelled as upgradeable or immutable? (%)
The relevant contracts are not identified as immutable / upgradeable.
20. Is the type of smart contract ownership clearly indicated? (%)
Ownership is not clearly indicated.
21. Are the protocol's smart contract change capabilities described? (%)
Smart contract change capabilities are not identified in any contracts.
22. Is the protocol's admin control information easy to understand? (%)
This information is not present, making evaluation impossible.
23. Is there sufficient Pause Control documentation? (%)
This protocol's pause control is not documented.
24. Is there sufficient Timelock documentation? (%)
This protocol has no timelock documentation. A mention of a day-long timelock is nevertheless identified in the GitHub repo at this location.
25. Is the Timelock of an adequate length? (Y/N)
The timelock is outside of our length requests. In order to reach full marks on this question, a justification on why 24 hours was chosen must be given.
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? (%)
Hop does not use an oracle because it is a bridge.
27. Is front running mitigated by this protocol? (Y/N)
Since Hop is a bridge, it cannot be front run.
28. Can flashloan attacks be applied to the protocol, and if so, are those flashloan attack risks mitigated? (Y/N)
This protocol documents no flashloan attack countermeasures.
1// SPDX-License-Identifier: MIT
2
3pragma solidity 0.6.12;
4pragma experimental ABIEncoderV2;
5
6import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
7import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
8import "./Bridge.sol";
9import "./L2_Bridge.sol";
10
11/**
12 * @dev L1_Bridge is responsible for the bonding and challenging of TransferRoots. All TransferRoots
13 * originate in the L1_Bridge through `bondTransferRoot` and are propagated up to destination L2s.
14 */
15
16abstract contract L1_Bridge is Bridge {
17 using SafeERC20 for IERC20;
18
19 struct TransferBond {
20 address bonder;
21 uint256 createdAt;
22 uint256 totalAmount;
23 uint256 challengeStartTime;
24 address challenger;
25 bool challengeResolved;
26 }
27
28 /* ========== Constants ========== */
29
30 address constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
31
32 /* ========== State ========== */
33
34 address public immutable token;
35 mapping(uint256 => mapping(bytes32 => uint256)) public transferRootCommittedAt;
36 mapping(bytes32 => TransferBond) public transferBonds;
37 mapping(uint256 => mapping(address => uint256)) public timeSlotToAmountBonded;
38 mapping(uint256 => uint256) public chainBalance;
39
40 /* ========== Config State ========== */
41
42 mapping(uint256 => address) public xDomainConnectors;
43 mapping(uint256 => bool) public isChainIdPaused;
44 uint256 public challengePeriod = 1 days;
45 uint256 public challengeResolutionPeriod = 10 days;
46 uint256 public minTransferRootBondDelay = 15 minutes;
47
48 uint256 public constant CHALLENGE_AMOUNT_DIVISOR = 10;
49 uint256 public constant TIME_SLOT_SIZE = 4 hours;
50
51 /* ========== Events ========== */
52
53 event TransferSentToL2(
54 uint256 indexed chainId,
55 address indexed recipient,
56 uint256 amount,
57 uint256 tokenIndex,
58 uint256 amountOutMin,
59 uint256 deadline,
60 address indexed relayer,
61 uint256 relayerFee
62 );
63
64 event TransferRootBonded (
65 bytes32 indexed root,
66 uint256 amount,
67 uint256 destinationChainid
68 );
69
70 event TransferRootConfirmed(
71 uint256 indexed originChainId,
72 uint256 indexed destinationChainId,
73 bytes32 indexed rootHash,
74 uint256 totalAmount
75 );
76
77 event TransferBondChallenged(
78 bytes32 indexed transferRootId,
79 bytes32 indexed rootHash,
80 uint256 originalAmount
81 );
82
83 event ChallengeResolved(
84 bytes32 indexed transferRootId,
85 bytes32 indexed rootHash,
86 uint256 originalAmount
87 );
88
89 /* ========== Modifiers ========== */
90
91 modifier onlyL2Bridge(uint256 chainId) {
92 require(msg.sender == xDomainConnectors[chainId], "L1_BRG: Caller must be bridge connector");
93 _;
94 }
95
96 constructor (
97 IBonderRegistry _registry,
98 address _token
99 )
100 public
101 Bridge(_registry)
102 {
103 token = _token;
104 }
105
106 /* ========== Send Functions ========== */
107
108 /**
109 * @notice `swapData` should contain all 0s when no swap is intended at the destination.
110 * @notice `amount` is the total amount the user wants to send including the relayer fee
111 * @dev Send tokens to a supported layer-2 to mint hToken and optionally swap the hToken in the
112 * AMM at the destination.
113 * @param chainId The chainId of the destination chain
114 * @param recipient The address receiving funds at the destination
115 * @param amount The amount being sent
116 * @param swapData The `tokenIndex`, `amountOutMin`, and `deadline` used for swaps
117 * @param relayer The address of the relayer at the destination.
118 * @param relayerFee The amount distributed to the relayer at the destination. This is subtracted from the `amount`.
119 */
120 function sendToL2(
121 uint256 chainId,
122 address recipient,
123 uint256 amount,
124 SwapData calldata swapData,
125 address relayer,
126 uint256 relayerFee
127 )
128 external
129 payable
130 {
131 address xDomainConnector = xDomainConnectors[chainId];
132 require(xDomainConnector != address(0), "L1_BRG: chainId not supported");
133 require(isChainIdPaused[chainId] == false, "L1_BRG: Sends to this chainId are paused");
134 require(amount > 0, "L1_BRG: Must transfer a non-zero amount");
135 require(amount >= relayerFee, "L1_BRG: Relayer fee cannot exceed amount");
136
137 _transferToBridge(msg.sender, amount);
138
139 chainBalance[chainId] = chainBalance[chainId].add(amount);
140
141 uint256 forwardedValue;
142 if (token == ETH_ADDRESS) {
143 forwardedValue = msg.value.sub(amount, "L1_BRG: Value is less than amount");
144 } else {
145 forwardedValue = msg.value;
146 }
147
148 L2_Bridge(xDomainConnector).distribute(
149 recipient,
150 amount,
151 swapData,
152 relayer,
153 relayerFee
154 );
155
156 emit TransferSentToL2(
157 chainId,
158 recipient,
159 amount,
160 swapData.tokenIndex,
161 swapData.amountOutMin,
162 swapData.deadline,
163 relayer,
164 relayerFee
165 );
166 }
167
168 /* ========== TransferRoot Functions ========== */
169
170 /**
171 * @dev Setting a TransferRoot is a two step process.
172 * @dev 1. The TransferRoot is bonded with `bondTransferRoot`. Withdrawals can now begin on L1
173 * @dev and recipient L2's
174 * @dev 2. The TransferRoot is confirmed after `confirmTransferRoot` is called by the l2 bridge
175 * @dev where the TransferRoot originated.
176 */
177
178 /**
179 * @dev Used by the Bonder to bond a TransferRoot and propagate it up to destination L2s
180 * @param rootHash The Merkle root of the TransferRoot Merkle tree
181 * @param destinationChainId The id of the destination chain
182 * @param totalAmount The amount destined for the destination chain
183 */
184 function bondTransferRoot(
185 bytes32 rootHash,
186 uint256 destinationChainId,
187 uint256 totalAmount
188 )
189 external
190 onlyBonder
191 requirePositiveBalance
192 {
193 _bondTransferRoot(rootHash, destinationChainId, totalAmount);
194 }
195
196 /**
197 * @dev Convenience function used by the Bonder to bond a TransferRoot and immediately settle it on L1
198 * @param rootHash The Merkle root of the TransferRoot Merkle tree
199 * @param destinationChainId The id of the destination chain
200 * @param transferIds All transferIds in the TransferRoot in order
201 * @param totalAmount The amount destined for the destination chain
202 */
203 function bondTransferRootAndSettle(
204 bytes32 rootHash,
205 uint256 destinationChainId,
206 // transferIds _must_ be calldata or it will be mutated by Lib_MerkleTree.getMerkleRoot
207 bytes32[] calldata transferIds,
208 uint256 totalAmount
209 )
210 external
211 onlyBonder
212 requirePositiveBalance
213 {
214 require(destinationChainId == getChainId(), "L1_BRG: bondTransferRootAndSettle is for L1 only");
215 _bondTransferRoot(rootHash, destinationChainId, totalAmount);
216 settleBondedWithdrawals(msg.sender, transferIds, totalAmount);
217 }
218
Tests to Code: 15611 / 1392 = 1121 %