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://github.com/trusttoken/smart-contracts#readme, as indicated in the Appendix.
2. Is the code actively being used? (%)
Activity is over 10 internal transactions a day on contract Registry.sol, as indicated in the Appendix.
3. Is there a public software repository? (Y/N)
GitHub: https://github.com/trusttoken/smart-contracts GitHub link is available in TrueFi's Litepaper
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? (%)
TrustToken's smart contracts have 15 branches and 1427 commits.
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)
The team can be found in TrueFi's GitHub page.
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)
Yes, most major functions have documentation in the repository's "docs" subfolder.
8. Does the software function documentation fully (100%) cover the deployed contracts? (%)
All function documentation is found in TrueFi's GitHub repository.
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 (%)
TrueFi's GitHub repository gives a lear association between the code and documents via non 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) (%)
As per TrueFi's GitHub repository, their smart contracts have a coverage of 82%.
13. Scripts and instructions to run the tests? (Y/N)
Scripts can be found at https://github.com/trusttoken/smart-contracts/tree/main/scripts.
14. Report of the results (%)
The coveralls test report is available at https://coveralls.io/github/trusttoken/smart-contracts?branch=main.
15. Formal Verification test done (%)
No evidence of formal verification.
16. Stress Testing environment (%)
There is evidence of a stress testing environment at https://github.com/trusttoken/smart-contracts/blob/main/deployments-ropsten.json.
This section looks at the 3rd party software audits done. It is explained in this document.
17. Did 3rd Party audits take place? (%)
TrueFi has had multiple audits, found here. Out of those, two of the ImmuneBytes audits were performed before the launch of v4 on August 18th 2021, and the third ImmuneBytes audit was performed post-launch.
18. Is the bug bounty acceptable high? (%)
An active Bug bounty program can be found at https://github.com/trusttoken/bug-bounty.
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 (%)
Governance access control information was found in their GitHub repo at https://github.com/trusttoken/smart-contracts/tree/main/docs/governance, as well as in their Medium blog at https://blog.trusttoken.com/truefi-v2-improved-staking-liquid-exit-on-chain-governance-45f144b8ec01.
20. Is the information clear and complete (%)
21. Is the information in non-technical terms that pertain to the investments (%)
Admin control information is only available in software-specific language.
22. Is there Pause Control documentation including records of tests (%)
There is no documentation to be found on pause control. However, it can be found in their GitHub repository without proper documentation at https://github.com/trusttoken/smart-contracts/blob/main/docs/governance/Pauser.md.
1// SPDX-License-Identifier: MIT
2pragma solidity 0.6.10;
3
4import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
6
7import {Initializable} from "../common/Initializable.sol";
8import {ITrueDistributor} from "./interface/ITrueDistributor.sol";
9import {ITrueFarm} from "./interface/ITrueFarm.sol";
10
11/**
12 * @title TrueFarm
13 * @notice Deposit liquidity tokens to earn TRU rewards over time
14 * @dev Staking pool where tokens are staked for TRU rewards
15 * A Distributor contract decides how much TRU a farm can earn over time
16 */
17contract TrueFarm is ITrueFarm, Initializable {
18 using SafeMath for uint256;
19 uint256 constant PRECISION = 1e30;
20
21 // ================ WARNING ==================
22 // ===== THIS CONTRACT IS INITIALIZABLE ======
23 // === STORAGE VARIABLES ARE DECLARED BELOW ==
24 / REMOVAL OR REORDER OF VARIABLES WILL RESULT
25 / ========= IN STORAGE CORRUPTION ===========
26
27 IERC20 public override stakingToken;
28 IERC20 public override trustToken;
29 ITrueDistributor public override trueDistributor;
30 string public override name;
31
32 // track stakes
33 uint256 public override totalStaked;
34 mapping(address => uint256) public staked;
35
36 // track overall cumulative rewards
37 uint256 public cumulativeRewardPerToken;
38 // track previous cumulate rewards for accounts
39 mapping(address => uint256) public previousCumulatedRewardPerToken;
40 // track claimable rewards for accounts
41 mapping(address => uint256) public claimableReward;
42
43 // track total rewards
44 uint256 public totalClaimedRewards;
45 uint256 public totalFarmRewards;
46
47 // ======= STORAGE DECLARATION END ============
48
49 /**
50 * @dev Emitted when an account stakes
51 * @param who Account staking
52 * @param amountStaked Amount of tokens staked
53 */
54 event Stake(address indexed who, uint256 amountStaked);
55
56 /**
57 * @dev Emitted when an account unstakes
58 * @param who Account unstaking
59 * @param amountUnstaked Amount of tokens unstaked
60 */
61 event Unstake(address indexed who, uint256 amountUnstaked);
62
63 /**
64 * @dev Emitted when an account claims TRU rewards
65 * @param who Account claiming
66 * @param amountClaimed Amount of TRU claimed
67 */
68 event Claim(address indexed who, uint256 amountClaimed);
69
70 /**
71 * @dev Initialize staking pool with a Distributor contract
72 * The distributor contract calculates how much TRU rewards this contract
73 * gets, and stores TRU for distribution.
74 * @param _stakingToken Token to stake
75 * @param _trueDistributor Distributor contract
76 * @param _name Farm name
77 */
78 function initialize(
79 IERC20 _stakingToken,
80 ITrueDistributor _trueDistributor,
81 string memory _name
82 ) public initializer {
83 stakingToken = _stakingToken;
84 trueDistributor = _trueDistributor;
85 trustToken = _trueDistributor.trustToken();
86 name = _name;
87 require(trueDistributor.farm() == address(this), "TrueFarm: Distributor farm is not set");
88 }
89
90 /**
91 * @dev Stake tokens for TRU rewards.
92 * Also claims any existing rewards.
93 * @param amount Amount of tokens to stake
94 */
95 function stake(uint256 amount) external override update {
96 if (claimableReward[msg.sender] > 0) {
97 _claim();
98 }
99 staked[msg.sender] = staked[msg.sender].add(amount);
100 totalStaked = totalStaked.add(amount);
101 require(stakingToken.transferFrom(msg.sender, address(this), amount));
102 emit Stake(msg.sender, amount);
103 }
104
105 /**
106 * @dev Internal unstake function
107 * @param amount Amount of tokens to unstake
108 */
109 function _unstake(uint256 amount) internal {
110 require(amount <= staked[msg.sender], "TrueFarm: Cannot withdraw amount bigger than available balance");
111 staked[msg.sender] = staked[msg.sender].sub(amount);
112 totalStaked = totalStaked.sub(amount);
113 require(stakingToken.transfer(msg.sender, amount));
114 emit Unstake(msg.sender, amount);
115 }
116
117 /**
118 * @dev Internal claim function
119 */
120 function _claim() internal {
121 totalClaimedRewards = totalClaimedRewards.add(claimableReward[msg.sender]);
122 uint256 rewardToClaim = claimableReward[msg.sender];
123 claimableReward[msg.sender] = 0;
124 require(trustToken.transfer(msg.sender, rewardToClaim));
125 emit Claim(msg.sender, rewardToClaim);
126 }
127
128 /**
129 * @dev Remove staked tokens
130 * @param amount Amount of tokens to unstake
131 */
132 function unstake(uint256 amount) external override update {
133 _unstake(amount);
134 }
135
136 /**
137 * @dev Claim TRU rewards
138 */
139 function claim() external override update {
140 _claim();
141 }
142
143 /**
144 * @dev Unstake amount and claim rewards
145 * @param amount Amount of tokens to unstake
146 */
147 function exit(uint256 amount) external override update {
148 _unstake(amount);
149 _claim();
150 }
151
152 /**
153 * @dev View to estimate the claimable reward for an account
154 * @return claimable rewards for account
155 */
156 function claimable(address account) external view returns (uint256) {
157 if (staked[account] == 0) {
158 return claimableReward[account];
159 }
160 // estimate pending reward from distributor
161 uint256 pending = trueDistributor.nextDistribution();
162 // calculate total rewards (including pending)
163 uint256 newTotalFarmRewards = trustToken.balanceOf(address(this)).add(pending).add(totalClaimedRewards).mul(PRECISION);
164 // calculate block reward
165 uint256 totalBlockReward = newTotalFarmRewards.sub(totalFarmRewards);
166 // calculate next cumulative reward per token
167 uint256 nextcumulativeRewardPerToken = cumulativeRewardPerToken.add(totalBlockReward.div(totalStaked));
168 // return claimable reward for this account
169 // prettier-ignore
170 return claimableReward[account].add(
171 staked[account].mul(nextcumulativeRewardPerToken.sub(previousCumulatedRewardPerToken[account])).div(PRECISION));
172 }
173
174 /**
175 * @dev Update state and get TRU from distributor
176 */
177 modifier update() {
178 // pull TRU from distributor
179 // only pull if there is distribution and distributor farm is set to this farm
180 if (trueDistributor.nextDistribution() > 0 && trueDistributor.farm() == address(this)) {
181 trueDistributor.distribute();
182 }
183 // calculate total rewards
184 uint256 newTotalFarmRewards = trustToken.balanceOf(address(this)).add(totalClaimedRewards).mul(PRECISION);
185 // calculate block reward
186 uint256 totalBlockReward = newTotalFarmRewards.sub(totalFarmRewards);
187 // update farm rewards
188 totalFarmRewards = newTotalFarmRewards;
189 // if there are stakers
190 if (totalStaked > 0) {
191 cumulativeRewardPerToken = cumulativeRewardPerToken.add(totalBlockReward.div(totalStaked));
192 }
193 // update claimable reward for sender
194 claimableReward[msg.sender] = claimableReward[msg.sender].add(
195 staked[msg.sender].mul(cumulativeRewardPerToken.sub(previousCumulatedRewardPerToken[msg.sender])).div(PRECISION)
196 );
197 // update previous cumulative for sender
198 previousCumulatedRewardPerToken[msg.sender] = cumulativeRewardPerToken;
199 _;
200 }
201}
Comments to Code: 5087 / 7765 = 66 %
Tests to Code: 17467 / 7765 = 225 %