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 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.kine.io/whitepaper/contract-address, as indicated in the Appendix.
2. Is the code actively being used? (%)
Activity is over 10 transactions a day on contract Unitroller.sol (Controller), as indicated in the Appendix.
3. Is there a public software repository? (Y/N)
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? (%)
With 63 commits and 3 branches, this is a semi-healthy software repository.
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.
7. Are the basic software functions documented? (Y/N)
The basic software functions are documented at https://docs.kine.io/whitepaper/kine-the-liquidity-pool-protocol and https://github.com/Kine-Technology/kine-protocol/blob/main/docs/contracts_overview.md.
8. Does the software function documentation fully (100%) cover the deployed contracts? (%)
All contracts and software functions are documented at https://github.com/Kine-Technology/kine-protocol/tree/main/docs.
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 (%)
Although Kine Protocol does a good job at indicating how the software functions interact with each other, what that looks like, and what it does, they do not explicitly lead it back to their own source code. Therefore, it comes non-explicit traceability.
11. Full test suite (Covers all the deployed code) (%)
There is no testing suite in the Kine Protocol GitHub repository.
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) (%)
There is no evidence of a Kine Protocol code coverage in any of their documentation or in their PeckShield audit report.
13. Scripts and instructions to run the tests? (Y/N)
No scripts and instructions to run were found
14. Report of the results (%)
There is no evidence of a test result report in any of the Kine Protocol documentation.
15. Formal Verification test done (%)
There is no evidence of a Kine Protocol Formal Verification test in any of their documentation.
16. Stress Testing environment (%)
There is evidence of Kine Protocol's testnet smart contract usage at https://github.com/Kine-Technology/kine-protocol/tree/main/network.
This section looks at the 3rd party software audits done. It is explained in this document.
17. Did 3rd Party audits take place? (%)
PeckShield published a Kine Protocol audit report on February 6th 2021, which was before their mainnet deployment on March 23rd.
18. Is the bug bounty acceptable high? (%)
There is no evidence of a Kine Protocol Bug Bounty program in any of their documentation or in further web searches.
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 (%)
There are currently no access controls documented in the Kine Protocol documentation as they do not currently have a governance model. However, they have stated that this will be a future addition to their ecosystem.
20. Is the information clear and complete (%)
There are currently no access controls documented in the Kine Protocol documentation as they do not currently have a governance model. However, they have stated that this will be a future addition to their ecosystem.
21. Is the information in non-technical terms that pertain to the investments (%)
There are currently no access controls documented in the Kine Protocol documentation as they do not currently have a governance model. However, they have stated that this will be a future addition to their ecosystem.
22. Is there Pause Control documentation including records of tests (%)
Pause Guardian is mentioned in the Kine Protocol documentation, but no details on capability or test records.
1contract Controller is ControllerStorage, KineControllerInterface, Exponential, ControllerErrorReporter {
2 /// @notice Emitted when an admin supports a market
3 event MarketListed(KToken kToken);
4
5 /// @notice Emitted when an account enters a market
6 event MarketEntered(KToken kToken, address account);
7
8 /// @notice Emitted when an account exits a market
9 event MarketExited(KToken kToken, address account);
10
11 /// @notice Emitted when close factor is changed by admin
12 event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa);
13
14 /// @notice Emitted when a collateral factor is changed by admin
15 event NewCollateralFactor(KToken kToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa);
16
17 /// @notice Emitted when liquidation incentive is changed by admin
18 event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa);
19
20 /// @notice Emitted when redemption params is changed by admin
21 event NewRedemptionInitialPunishment(uint oldRedemptionInitialPunishmentMantissa, uint newRedemptionInitialPunishmentMantissa);
22
23 /// @notice Emitted when price oracle is changed
24 event NewPriceOracle(KineOracleInterface oldPriceOracle, KineOracleInterface newPriceOracle);
25
26 /// @notice Emitted when pause guardian is changed
27 event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian);
28
29 /// @notice Emitted when an action is paused globally
30 event ActionPaused(string action, bool pauseState);
31
32 /// @notice Emitted when an action is paused on a market
33 event ActionPaused(KToken kToken, string action, bool pauseState);
34
35 /// @notice Emitted when borrow cap for a kToken is changed
36 event NewBorrowCap(KToken indexed kToken, uint newBorrowCap);
37
38 /// @notice Emitted when supply cap for a kToken is changed
39 event NewSupplyCap(KToken indexed kToken, uint newSupplyCap);
40
41 /// @notice Emitted when borrow/supply cap guardian is changed
42 event NewCapGuardian(address oldCapGuardian, address newCapGuardian);
43
44 // closeFactorMantissa must be strictly greater than this value
45 uint internal constant closeFactorMinMantissa = 0.05e18; // 0.05
46
47 // closeFactorMantissa must not exceed this value
48 uint internal constant closeFactorMaxMantissa = 0.9e18; // 0.9
49
50 // liquidationIncentiveMantissa must be no less than this value
51 uint internal constant liquidationIncentiveMinMantissa = 1.0e18; // 1.0
52
53 // liquidationIncentiveMantissa must be no greater than this value
54 uint internal constant liquidationIncentiveMaxMantissa = 1.5e18; // 1.5
55
56 // No collateralFactorMantissa may exceed this value
57 uint internal constant collateralFactorMaxMantissa = 0.9e18; // 0.9
58
59 constructor() public {
60 admin = msg.sender;
61 }
62
63 modifier onlyAdmin() {
64 require(msg.sender == admin, "only admin can call this function");
65 _;
66 }
67
68 /*** Assets You Are In ***/
69
70 /**
71 * @notice Returns the assets an account has entered
72 * @param account The address of the account to pull assets for
73 * @return A dynamic list with the assets the account has entered
74 */
75 function getAssetsIn(address account) external view returns (KToken[] memory) {
76 KToken[] memory assetsIn = accountAssets[account];
77
78 return assetsIn;
79 }
80
81 /**
82 * @notice Returns whether the given account is entered in the given asset
83 * @param account The address of the account to check
84 * @param kToken The kToken to check
85 * @return True if the account is in the asset, otherwise false.
86 */
87 function checkMembership(address account, KToken kToken) external view returns (bool) {
88 return markets[address(kToken)].accountMembership[account];
89 }
90
91 /**
92 * @notice Add assets to be included in account liquidity calculation
93 * @param kTokens The list of addresses of the kToken markets to be enabled
94 * @dev will revert if any market entering failed
95 */
96 function enterMarkets(address[] memory kTokens) public {
97 uint len = kTokens.length;
98 for (uint i = 0; i < len; i++) {
99 KToken kToken = KToken(kTokens[i]);
100 addToMarketInternal(kToken, msg.sender);
101 }
102 }
103
104 /**
105 * @notice Add the market to the borrower's "assets in" for liquidity calculations
106 * @param kToken The market to enter
107 * @param borrower The address of the account to modify
108 */
109 function addToMarketInternal(KToken kToken, address borrower) internal {
110 Market storage marketToJoin = markets[address(kToken)];
111
112 require(marketToJoin.isListed, MARKET_NOT_LISTED);
113
114 if (marketToJoin.accountMembership[borrower] == true) {
115 // already joined
116 return;
117 }
118
119 // survived the gauntlet, add to list
120 // NOTE: we store these somewhat redundantly as a significant optimization
121 // this avoids having to iterate through the list for the most common use cases
122 / that is, only when we need to perform liquidity checks
123 / and not whenever we want to check if an account is in a particular market
124 marketToJoin.accountMembership[borrower] = true;
125 accountAssets[borrower].push(kToken);
126
127 emit MarketEntered(kToken, borrower);
128 }
129
130 /**
131 * @notice Removes asset from sender's account liquidity calculation
132 * @dev Sender must not have an outstanding borrow balance in the asset,
133 * or be providing necessary collateral for an outstanding borrow.
134 * @param kTokenAddress The address of the asset to be removed
135 */
136 function exitMarket(address kTokenAddress) external {
137 KToken kToken = KToken(kTokenAddress);
138 /* Get sender tokensHeld and amountOwed underlying from the kToken */
139 (uint tokensHeld, uint amountOwed) = kToken.getAccountSnapshot(msg.sender);
140
141 /* Fail if the sender has a borrow balance */
142 require(amountOwed == 0, EXIT_MARKET_BALANCE_OWED);
143
144 /* Fail if the sender is not permitted to redeem all of their tokens */
145 (bool allowed,) = redeemAllowedInternal(kTokenAddress, msg.sender, tokensHeld);
146 require(allowed, EXIT_MARKET_REJECTION);
147
148 Market storage marketToExit = markets[address(kToken)];
149
150 /* Succeed true if the sender is not already ‘in’ the market */
151 if (!marketToExit.accountMembership[msg.sender]) {
152 return;
153 }
154
155 /* Set kToken account membership to false */
156 delete marketToExit.accountMembership[msg.sender];
157
158 /* Delete kToken from the account’s list of assets */
159 // load into memory for faster iteration
160 KToken[] memory userAssetList = accountAssets[msg.sender];
161 uint len = userAssetList.length;
162 uint assetIndex = len;
163 for (uint i = 0; i < len; i++) {
164 if (userAssetList[i] == kToken) {
165 assetIndex = i;
166 break;
167 }
168 }
169
170 // We *must* have found the asset in the list or our redundant data structure is broken
171 require(assetIndex < len, "accountAssets array broken");
172
173 // copy last item in list to location of item to be removed, reduce length by 1
174 KToken[] storage storedList = accountAssets[msg.sender];
175 if (assetIndex != storedList.length - 1) {
176 storedList[assetIndex] = storedList[storedList.length - 1];
177 }
178 storedList.length--;
179
180 emit MarketExited(kToken, msg.sender);
181 }
182
Comments to Code: 3322 / 4760 = 70 %