If you notice some outdated information please let us know!
FAIL
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? (%)
2. How active is the primary contract? (%)
Contract MasterChef.sol is used at least 1164 times per day during the last month, as indicated in the Appendix.
3. Does the protocol have a public software repository? (Y/N)
https://github.com/pancakeswap/pancake-smart-contracts
4. Is there a development history visible? (%)
PancakeSwap's contracts repository only has 1 commit, although the commit has 428 changed files with 116,992 additions.
5. Is the team public (not anonymous)?
The PancakeSwap team operates pseudonymously as outlined here.
This section looks at the software documentation. The document explaining these questions is here.
6. Is there a whitepaper? (Y/N)
Location: https://docs.pancakeswap.finance/code/smart-contracts/pancakeswap-exchange/factory-v2
7. Is the protocol's software architecture documented? (Y/N)
This protocol's software architecture is not documented.
8. Does the software documentation fully cover the deployed contracts' source code? (%)
The following contracts have function documentation. PancakeSwapLotteryV2.sol PancakeRouter V2.sol PancakeFactory V2.sol All other contracts in the repository (57 others) have no function/software documentation. Although functions are on average undocumented, the documented contracts are the most important ones. With the previous points considered, I will assign a 25% for software function documentation.
9. Is it possible to trace the documented software to its implementation in the protocol's source code? (%)
There is implicit traceability between software documentation and implemented code. Given that only a limited amount of software functions are documented, a score reduced proportionally will be awarded in line with the amount covered by software function documentation.
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 10029/22084= ~220% 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%. However, the reviewer's best judgement is the final deciding factor.
11. How covered is the protocol's code? (%)
PancakeSwap does not document tests for coverage. However, there's evidence of good testing in this repository. We will award points for this.
12. Does the protocol provide scripts and instructions to run their tests? (Y/N)
PancakeSwap does not document instructions to run tests.
13. Is there a detailed report of the protocol's test results?(%)
Pancakeswap documents a test report in their smart contract repository CLI. However, since this cannot be expanded for verification, we will not award points.
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)
No addresses or documentation in relation to testnet deployments can be located.
This section looks at the 3rd party software audits done. It is explained in this document.
16. Is the protocol sufficiently audited? (%)
The PancakeSwap deployer was deployed on September 15th 2020. PancakeSwap was audited by Slowmist 3 times; Once for overall security on May 12th 2021, once for Auto-CAKE pool security on May 21st 2021, and once for Lottery V2 on June 16th 2021. In addition, PancakeSwap was audited by Certik on October 13th 2020. LotteryV2 was re-audited by Peckshield on July 7th 2021.
17. Is the bounty value acceptably high (%)
This protocol offers an active bug bounty of $1M for smart contract vulnerabilities. With an additional maximum of $7500 for website and app bugs.
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 documented at this location. This was quick to find.
19. Are relevant contracts clearly labelled as upgradeable or immutable? (%)
The relevant contracts are identified as upgradeable through a 3/6 Gnosis multisig, as identified here.
20. Is the type of smart contract ownership clearly indicated? (%)
Ownership is clearly indicated in as shown here for relevant contracts.
21. Are the protocol's smart contract change capabilities described? (%)
The full extent of the contracts' change capabilities is not explicitly described, yet it can be assumed that they are mostly completely upgradeable through their 3/6 multisig. This proven in contract code.
22. Is the protocol's admin control information easy to understand? (%)
Admin control is written in easy to interpret language.
23. Is there sufficient Pause Control documentation? (%)
No pause control information is documented.
24. Is there sufficient Timelock documentation? (%)
No timelock information is documented. By reading the contract code, we learned there is a 6 hour timelock.
25. Is the Timelock of an adequate length? (Y/N)
No timelock information is documented.
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? (%)
No oracle information could be found other than a mention of Uniswap V2 in "pancake-smart-contracts/projects/exchange-protocol/"'s README. Although it is widely known that PancakeSwap is a 1:1 fork of Uniswap, this should be documented in a far more concise fashion. As a decentralised exchange, this information should be explained.
27. Is front running mitigated by this protocol? (Y/N)
No frontrunning information could be found.
28. Can flashloan attacks be applied to the protocol, and if so, are those flashloan attack risks mitigated? (Y/N)
No information relating to flashloan price manipulation mitigation can be found.
1// SPDX-License-Identifier: MIT
2pragma solidity 0.6.12;
3
4import "@openzeppelin/contracts/access/Ownable.sol";
5import "@openzeppelin/contracts/math/SafeMath.sol";
6import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
7import "@openzeppelin/contracts/utils/Pausable.sol";
8import "./interfaces/IMasterChef.sol";
9
10contract CakeVault is Ownable, Pausable {
11 using SafeERC20 for IERC20;
12 using SafeMath for uint256;
13
14 struct UserInfo {
15 uint256 shares; // number of shares for a user
16 uint256 lastDepositedTime; // keeps track of deposited time for potential penalty
17 uint256 cakeAtLastUserAction; // keeps track of cake deposited at the last user action
18 uint256 lastUserActionTime; // keeps track of the last user action time
19 }
20
21 IERC20 public immutable token; // Cake token
22 IERC20 public immutable receiptToken; // Syrup token
23
24 IMasterChef public immutable masterchef;
25
26 mapping(address => UserInfo) public userInfo;
27
28 uint256 public totalShares;
29 uint256 public lastHarvestedTime;
30 address public admin;
31 address public treasury;
32
33 uint256 public constant MAX_PERFORMANCE_FEE = 500; // 5%
34 uint256 public constant MAX_CALL_FEE = 100; // 1%
35 uint256 public constant MAX_WITHDRAW_FEE = 100; // 1%
36 uint256 public constant MAX_WITHDRAW_FEE_PERIOD = 72 hours; // 3 days
37
38 uint256 public performanceFee = 200; // 2%
39 uint256 public callFee = 25; // 0.25%
40 uint256 public withdrawFee = 10; // 0.1%
41 uint256 public withdrawFeePeriod = 72 hours; // 3 days
42
43 event Deposit(address indexed sender, uint256 amount, uint256 shares, uint256 lastDepositedTime);
44 event Withdraw(address indexed sender, uint256 amount, uint256 shares);
45 event Harvest(address indexed sender, uint256 performanceFee, uint256 callFee);
46 event Pause();
47 event Unpause();
48
49 /**
50 * @notice Constructor
51 * @param _token: Cake token contract
52 * @param _receiptToken: Syrup token contract
53 * @param _masterchef: MasterChef contract
54 * @param _admin: address of the admin
55 * @param _treasury: address of the treasury (collects fees)
56 */
57 constructor(
58 IERC20 _token,
59 IERC20 _receiptToken,
60 IMasterChef _masterchef,
61 address _admin,
62 address _treasury
63 ) public {
64 token = _token;
65 receiptToken = _receiptToken;
66 masterchef = _masterchef;
67 admin = _admin;
68 treasury = _treasury;
69
70 // Infinite approve
71 IERC20(_token).safeApprove(address(_masterchef), uint256(-1));
72 }
73
74 /**
75 * @notice Checks if the msg.sender is the admin address
76 */
77 modifier onlyAdmin() {
78 require(msg.sender == admin, "admin: wut?");
79 _;
80 }
81
82 /**
83 * @notice Checks if the msg.sender is a contract or a proxy
84 */
85 modifier notContract() {
86 require(!_isContract(msg.sender), "contract not allowed");
87 require(msg.sender == tx.origin, "proxy contract not allowed");
88 _;
89 }
90
91 /**
92 * @notice Deposits funds into the Cake Vault
93 * @dev Only possible when contract not paused.
94 * @param _amount: number of tokens to deposit (in CAKE)
95 */
96 function deposit(uint256 _amount) external whenNotPaused notContract {
97 require(_amount > 0, "Nothing to deposit");
98
99 uint256 pool = balanceOf();
100 token.safeTransferFrom(msg.sender, address(this), _amount);
101 uint256 currentShares = 0;
102 if (totalShares != 0) {
103 currentShares = (_amount.mul(totalShares)).div(pool);
104 } else {
105 currentShares = _amount;
106 }
107 UserInfo storage user = userInfo[msg.sender];
108
109 user.shares = user.shares.add(currentShares);
110 user.lastDepositedTime = block.timestamp;
111
112 totalShares = totalShares.add(currentShares);
113
114 user.cakeAtLastUserAction = user.shares.mul(balanceOf()).div(totalShares);
115 user.lastUserActionTime = block.timestamp;
116
117 _earn();
118
119 emit Deposit(msg.sender, _amount, currentShares, block.timestamp);
120 }
121
122 /**
123 * @notice Withdraws all funds for a user
124 */
125 function withdrawAll() external notContract {
126 withdraw(userInfo[msg.sender].shares);
127 }
128
129 /**
130 * @notice Reinvests CAKE tokens into MasterChef
131 * @dev Only possible when contract not paused.
132 */
133 function harvest() external notContract whenNotPaused {
134 IMasterChef(masterchef).leaveStaking(0);
135
136 uint256 bal = available();
137 uint256 currentPerformanceFee = bal.mul(performanceFee).div(10000);
138 token.safeTransfer(treasury, currentPerformanceFee);
139
140 uint256 currentCallFee = bal.mul(callFee).div(10000);
141 token.safeTransfer(msg.sender, currentCallFee);
142
143 _earn();
144
145 lastHarvestedTime = block.timestamp;
146
147 emit Harvest(msg.sender, currentPerformanceFee, currentCallFee);
148 }
149
150 /**
151 * @notice Sets admin address
152 * @dev Only callable by the contract owner.
153 */
154 function setAdmin(address _admin) external onlyOwner {
155 require(_admin != address(0), "Cannot be zero address");
156 admin = _admin;
157 }
158
159 /**
160 * @notice Sets treasury address
161 * @dev Only callable by the contract owner.
162 */
163 function setTreasury(address _treasury) external onlyOwner {
164 require(_treasury != address(0), "Cannot be zero address");
165 treasury = _treasury;
166 }
167
168 /**
169 * @notice Sets performance fee
170 * @dev Only callable by the contract admin.
171 */
172 function setPerformanceFee(uint256 _performanceFee) external onlyAdmin {
173 require(_performanceFee <= MAX_PERFORMANCE_FEE, "performanceFee cannot be more than MAX_PERFORMANCE_FEE");
174 performanceFee = _performanceFee;
175 }
176
177 /**
178 * @notice Sets call fee
179 * @dev Only callable by the contract admin.
180 */
181 function setCallFee(uint256 _callFee) external onlyAdmin {
182 require(_callFee <= MAX_CALL_FEE, "callFee cannot be more than MAX_CALL_FEE");
183 callFee = _callFee;
184 }
185
186 /**
187 * @notice Sets withdraw fee
188 * @dev Only callable by the contract admin.
189 */
190 function setWithdrawFee(uint256 _withdrawFee) external onlyAdmin {
191 require(_withdrawFee <= MAX_WITHDRAW_FEE, "withdrawFee cannot be more than MAX_WITHDRAW_FEE");
192 withdrawFee = _withdrawFee;
193 }
194
195 /**
196 * @notice Sets withdraw fee period
197 * @dev Only callable by the contract admin.
198 */
199 function setWithdrawFeePeriod(uint256 _withdrawFeePeriod) external onlyAdmin {
200 require(
201 _withdrawFeePeriod <= MAX_WITHDRAW_FEE_PERIOD,
202 "withdrawFeePeriod cannot be more than MAX_WITHDRAW_FEE_PERIOD"
203 );
204 withdrawFeePeriod = _withdrawFeePeriod;
205 }
206
207 /**
208 * @notice Withdraws from MasterChef to Vault without caring about rewards.
209 * @dev EMERGENCY ONLY. Only callable by the contract admin.
210 */
211 function emergencyWithdraw() external onlyAdmin {
212 IMasterChef(masterchef).emergencyWithdraw(0);
213 }
214
215 /**
216 * @notice Withdraw unexpected tokens sent to the Cake Vault
217 */
218 function inCaseTokensGetStuck(address _token) external onlyAdmin {
219 require(_token != address(token), "Token cannot be same as deposit token");
220 require(_token != address(receiptToken), "Token cannot be same as receipt token");
221
222 uint256 amount = IERC20(_token).balanceOf(address(this));
223 IERC20(_token).safeTransfer(msg.sender, amount);
224 }
225
226 /**
227 * @notice Triggers stopped state
228 * @dev Only possible when contract not paused.
229 */
230 function pause() external onlyAdmin whenNotPaused {
231 _pause();
232 emit Pause();
233 }
234
Tests to Code: 22084 / 10029 = 220 %