From 882f065424d7eae1d4ed456dad65f56cdfb206c6 Mon Sep 17 00:00:00 2001 From: hal <61718761+hal909@users.noreply.github.com> Date: Thu, 18 Feb 2021 15:36:53 -0700 Subject: [PATCH] 2.0 documentation (#503) * 2.0 docs * moar docs Co-authored-by: Hal Hyatt --- contracts/governance/GovernorAlpha.sol | 5 -- contracts/governance/StkTruToken.sol | 14 ++++++ contracts/governance/Timelock.sol | 1 - contracts/governance/VoteToken.sol | 49 ++++++++++++++++++- contracts/truefi/Liquidator.sol | 2 + contracts/truefi/TrueLender.sol | 3 ++ contracts/truefi/TrueRatingAgencyV2.sol | 3 +- .../distributors/LinearTrueDistributor.sol | 1 + 8 files changed, 70 insertions(+), 8 deletions(-) diff --git a/contracts/governance/GovernorAlpha.sol b/contracts/governance/GovernorAlpha.sol index 884783697..b270f7e47 100644 --- a/contracts/governance/GovernorAlpha.sol +++ b/contracts/governance/GovernorAlpha.sol @@ -19,15 +19,12 @@ import {IVoteToken} from "./interface/IVoteToken.sol"; contract GovernorAlpha is ClaimableContract { // @notice The name of this contract - // OLD: string public constant name = "Compound Governor Alpha"; string public constant name = "TrustToken Governor Alpha"; // @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed - // OLD: function quorumVotes() public pure returns (uint) { return 400000e18; } // 400,000 = 4% of Comp function quorumVotes() public pure returns (uint) { return 10000000e8; } // 10,000,000 Tru // @notice The number of votes required in order for a voter to become a proposer - // OLD: function proposalThreshold() public pure returns (uint) { return 100000e18; } // 100,000 = 1% of Comp function proposalThreshold() public pure returns (uint) { return 100000e8; } // 100,000 TRU // @notice The maximum number of actions that can be included in a proposal @@ -37,14 +34,12 @@ contract GovernorAlpha is ClaimableContract { function votingDelay() public pure returns (uint) { return 1; } // 1 block // @notice The duration of voting on a proposal, in blocks - // OLD: function votingPeriod() public pure returns (uint) { return 17280; } // ~3 days in blocks (assuming 15s blocks) uint public votingPeriod; // @notice The address of the TrustToken Protocol Timelock ITimelock public timelock; // @notice The address of the TrustToken governance token - // OLD: CompInterface public comp; IVoteToken public trustToken; // @notice The address of the stkTRU voting token diff --git a/contracts/governance/StkTruToken.sol b/contracts/governance/StkTruToken.sol index 23d38061c..c693c38e6 100644 --- a/contracts/governance/StkTruToken.sol +++ b/contracts/governance/StkTruToken.sol @@ -463,6 +463,11 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { } } + /** + * @dev Update claimable rewards for a token and account + * @param token Token to update claimable rewards for + * @param user Account to update claimable rewards for + */ function updateClaimableRewards(IERC20 token, address user) internal { // update claimable reward for sender if (balanceOf[user] > 0) { @@ -476,6 +481,10 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { farmRewards[token].previousCumulatedRewardPerToken[user] = farmRewards[token].cumulativeRewardPerToken; } + /** + * @dev Find next distribution index given a timestamp + * @param timestamp Timestamp to find next distribution index for + */ function findPositionForTimestamp(uint256 timestamp) internal view returns (uint32 i) { for (i = nextDistributionIndex; i < sortedScheduledRewardIndices.length; i++) { if (scheduledRewards[sortedScheduledRewardIndices[i]].timestamp > timestamp) { @@ -484,6 +493,11 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { } } + /** + * @dev internal function to insert distribution index in a sorted list + * @param index Index to insert at + * @param value Value at index + */ function insertAt(uint32 index, uint32 value) internal { sortedScheduledRewardIndices.push(0); for (uint32 j = uint32(sortedScheduledRewardIndices.length) - 1; j > index; j--) { diff --git a/contracts/governance/Timelock.sol b/contracts/governance/Timelock.sol index 4cddb9431..ad6bdb881 100644 --- a/contracts/governance/Timelock.sol +++ b/contracts/governance/Timelock.sol @@ -162,7 +162,6 @@ contract Timelock is ClaimableContract { callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data); } - // OLD: (bool success, bytes memory returnData) = target.call.value(value)(callData); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returnData) = target.call{value:value}(callData); require(success, "Timelock::executeTransaction: Transaction execution reverted."); diff --git a/contracts/governance/VoteToken.sol b/contracts/governance/VoteToken.sol index 091ebeeab..2b6b86681 100644 --- a/contracts/governance/VoteToken.sol +++ b/contracts/governance/VoteToken.sol @@ -9,12 +9,19 @@ // // Ctrl+f for OLD to see all the modifications. -// OLD: pragma solidity ^0.5.16; pragma solidity 0.6.10; import {ERC20} from "../trusttoken/common/ERC20.sol"; import {IVoteToken} from "./interface/IVoteToken.sol"; +/** + * @title VoteToken + * @notice Custom token which tracks voting power for governance + * @dev This is an abstraction of a fork of the Compound governance contract + * VoteToken is used by TRU and stkTRU to allow tracking voting power + * Checkpoints are created every time state is changed which record voting power + * Inherits standard ERC20 behavior + */ abstract contract VoteToken is ERC20, IVoteToken { bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); @@ -26,6 +33,9 @@ abstract contract VoteToken is ERC20, IVoteToken { return _delegate(msg.sender, delegatee); } + /** + * @dev Delegate votes using signature + */ function delegateBySig( address delegatee, uint256 nonce, @@ -44,11 +54,22 @@ abstract contract VoteToken is ERC20, IVoteToken { return _delegate(signatory, delegatee); } + /** + * @dev Get current voting power for an account + * @param account Account to get voting power for + * @return Voting power for an account + */ function getCurrentVotes(address account) public virtual override view returns (uint96) { uint32 nCheckpoints = numCheckpoints[account]; return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; } + /** + * @dev Get voting power at a specific block for an account + * @param account Account to get voting power for + * @param blockNumber Block to get voting power at + * @return Voting power for an account at specific block + */ function getPriorVotes(address account, uint256 blockNumber) public virtual override view returns (uint96) { require(blockNumber < block.number, "TrustToken::getPriorVotes: not yet determined"); @@ -83,6 +104,11 @@ abstract contract VoteToken is ERC20, IVoteToken { return checkpoints[account][lower].votes; } + /** + * @dev Internal function to delegate voting power to an account + * @param delegator Account to delegate votes from + * @param delegatee Account to delegate votes to + */ function _delegate(address delegator, address delegatee) internal { address currentDelegate = delegates[delegator]; // OLD: uint96 delegatorBalance = balanceOf(delegator); @@ -117,6 +143,9 @@ abstract contract VoteToken is ERC20, IVoteToken { _moveDelegates(delegates[account], address(0), safe96(amount, "StkTruToken: uint96 overflow")); } + /** + * @dev internal function to move delegates between accounts + */ function _moveDelegates( address srcRep, address dstRep, @@ -139,6 +168,9 @@ abstract contract VoteToken is ERC20, IVoteToken { } } + /** + * @dev internal function to write a checkpoint for voting power + */ function _writeCheckpoint( address delegatee, uint32 nCheckpoints, @@ -157,16 +189,25 @@ abstract contract VoteToken is ERC20, IVoteToken { emit DelegateVotesChanged(delegatee, oldVotes, newVotes); } + /** + * @dev internal function to convert from uint256 to uint32 + */ function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) { require(n < 2**32, errorMessage); return uint32(n); } + /** + * @dev internal function to convert from uint256 to uint96 + */ function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) { require(n < 2**96, errorMessage); return uint96(n); } + /** + * @dev internal safe math function to add two uint96 numbers + */ function add96( uint96 a, uint96 b, @@ -177,6 +218,9 @@ abstract contract VoteToken is ERC20, IVoteToken { return c; } + /** + * @dev internal safe math function to subtract two uint96 numbers + */ function sub96( uint96 a, uint96 b, @@ -186,6 +230,9 @@ abstract contract VoteToken is ERC20, IVoteToken { return a - b; } + /** + * @dev internal function to get chain ID + */ function getChainId() internal pure returns (uint256) { uint256 chainId; assembly { diff --git a/contracts/truefi/Liquidator.sol b/contracts/truefi/Liquidator.sol index 6ad956aa6..5c4c805a3 100644 --- a/contracts/truefi/Liquidator.sol +++ b/contracts/truefi/Liquidator.sol @@ -89,6 +89,7 @@ contract Liquidator is Ownable { /** * @dev Change oracle + * @param newOracle New oracle for liquidator */ function setOracle(ITruPriceOracle newOracle) external onlyOwner { // Check if new oracle implements method @@ -117,6 +118,7 @@ contract Liquidator is Ownable { /** * @dev Calculate amount of tru to be withdrawn from staking pool (not more than preset share) * @param deficit Amount of tusd lost on defaulted loan + * @return amount of TRU to be withdrawn on liquidation */ function getAmountToWithdraw(uint256 deficit) internal view returns (uint256) { uint256 stakingPoolSupply = stkTru.stakeSupply(); diff --git a/contracts/truefi/TrueLender.sol b/contracts/truefi/TrueLender.sol index d2bf2a418..b34330e00 100644 --- a/contracts/truefi/TrueLender.sol +++ b/contracts/truefi/TrueLender.sol @@ -334,6 +334,8 @@ contract TrueLender is ITrueLender, Ownable { /** * @dev Temporary fix for old LoanTokens with incorrect value calculation + * @param loan Loan to calculate value for + * @return value of a given loan */ function loanValue(ILoanToken loan) public view returns (uint256) { uint256 _balance = loan.balanceOf(address(this)); @@ -400,6 +402,7 @@ contract TrueLender is ITrueLender, Ownable { } } // If we reach this, it means loanToken was not present in _loans array + // This prevents invalid loans from being reclaimed revert("TrueLender: This loan has not been funded by the lender"); } diff --git a/contracts/truefi/TrueRatingAgencyV2.sol b/contracts/truefi/TrueRatingAgencyV2.sol index e0d1c9104..4d58242da 100644 --- a/contracts/truefi/TrueRatingAgencyV2.sol +++ b/contracts/truefi/TrueRatingAgencyV2.sol @@ -21,9 +21,10 @@ import {ITrueRatingAgencyV2} from "./interface/ITrueRatingAgencyV2.sol"; * TrueFi uses use a prediction market to signal how risky a loan is. * The Credit Prediction Market estimates the likelihood of a loan defaulting. * Any stkTRU holder can rate YES or NO and stake TRU as collateral on their rate. + * Voting weight is equal to delegated governance power (see VoteToken.sol) * If a loan is funded, TRU is rewarded as incentive for participation * Rating stkTRU in the prediction market allows raters to earn and claim TRU - * incentive when the loan is passed + * incentive when the loan is approved * * Voting Lifecycle: * - Borrowers can apply for loans at any time by deploying a LoanToken diff --git a/contracts/truefi/distributors/LinearTrueDistributor.sol b/contracts/truefi/distributors/LinearTrueDistributor.sol index f1813554f..4bbf08e7f 100644 --- a/contracts/truefi/distributors/LinearTrueDistributor.sol +++ b/contracts/truefi/distributors/LinearTrueDistributor.sol @@ -138,6 +138,7 @@ contract LinearTrueDistributor is ITrueDistributor, Ownable { /** * @dev Change amount of tokens distributed daily by changing total distributed amount + * @param dailyDistribution New daily distribution */ function setDailyDistribution(uint256 dailyDistribution) public onlyOwner { distribute();