From 14fed4d277e002e215084d511d2fb052b4cc90e0 Mon Sep 17 00:00:00 2001 From: hal <61718761+hal909@users.noreply.github.com> Date: Thu, 18 Feb 2021 23:09:25 -0700 Subject: [PATCH] Truefi 2.0 deploy (#505) * rating agency v2 distributor * truefi 2.0 deploy * linter * fix test * add docs * flatten * linter * documentation Co-authored-by: Hal Hyatt --- contracts/truefi/LoanFactory.sol | 4 +- contracts/truefi/TrueRatingAgencyV2.sol | 6 + .../distributors/ArbitraryDistributor.sol | 7 +- .../RatingAgencyV2Distributor.sol | 14 +- docs/avalanche/AvalancheTokenController.md | 461 +++++++ docs/avalanche/AvalancheTrueUSD.md | 39 + docs/governance/GovernorAlpha.md | 203 +++ docs/governance/StkTruToken.md | 284 ++++ docs/governance/Timelock.md | 105 ++ docs/governance/VoteToken.md | 123 ++ docs/governance/common/ClaimableContract.md | 60 + docs/governance/interface/ITimelock.md | 50 + docs/governance/interface/IVoteToken.md | 32 + .../interface/IVoteTokenWithERC20.md | 8 + docs/proxy/OwnedUpgradeabilityProxy.md | 119 ++ docs/proxy/TimeOwnedUpgradeabilityProxy.md | 42 + .../interface/IOwnedUpgradeabilityProxy.md | 44 + docs/registry/Registry.md | 147 ++ docs/registry/interface/IHasOwner.md | 20 + docs/registry/interface/IRegistry.md | 74 + docs/registry/interface/IRegistryClone.md | 14 + docs/registry/mocks/MockRegistrySubscriber.md | 20 + docs/registry/mocks/ProvisionalRegistry.md | 32 + .../registry/mocks/ProvisionalRegistryMock.md | 8 + docs/registry/mocks/RegistryMock.md | 21 + docs/true-currencies/DelegateERC20.md | 70 + docs/true-currencies/TokenController.md | 479 +++++++ docs/true-currencies/TrueCurrency.md | 98 ++ .../TrueCurrencyWithGasRefund.md | 16 + .../TrueCurrencyWithLegacyAutosweep.md | 31 + .../common/BurnableTokenWithBounds.md | 53 + .../common/ClaimableOwnable.md | 49 + docs/true-currencies/common/ERC20.md | 183 +++ docs/true-currencies/common/GasRefund.md | 34 + docs/true-currencies/common/ProxyStorage.md | 11 + docs/true-currencies/common/ReclaimerToken.md | 24 + docs/true-currencies/interface/IHasOwner.md | 20 + docs/true-currencies/interface/IHook.md | 14 + .../interface/IReclaimerToken.md | 20 + .../interface/ITrueCurrency.md | 38 + docs/true-currencies/mocks/ForceEther.md | 14 + docs/true-currencies/mocks/IDelegateERC20.md | 56 + .../mocks/MockDelegateERC20.md | 81 ++ .../mocks/MockGasRefundToken.md | 20 + docs/true-currencies/mocks/MockHook.md | 14 + .../true-currencies/mocks/MockTrueCurrency.md | 38 + .../mocks/MockTrueCurrencyWithAutosweep.md | 38 + .../mocks/MockTrueCurrencyWithDelegate.md | 76 + .../mocks/MockTrueCurrencyWithGasRefund.md | 38 + .../MockTrueCurrencyWithLegacyAutosweep.md | 31 + .../mocks/TokenControllerMock.md | 20 + .../mocks/TokenControllerPauseMock.md | 20 + docs/true-currencies/mocks/TokenFaucet.md | 14 + docs/true-currencies/tokens/TrueAUD.md | 34 + docs/true-currencies/tokens/TrueCAD.md | 33 + docs/true-currencies/tokens/TrueGBP.md | 33 + docs/true-currencies/tokens/TrueHKD.md | 33 + docs/true-currencies/tokens/TrueUSD.md | 33 + docs/true-gold/PausedTrueGold.md | 56 + docs/true-gold/Reclaimable.md | 26 + docs/true-gold/TrueGold.md | 44 + docs/true-gold/TrueGoldController.md | 435 ++++++ docs/true-gold/TrueMintableBurnable.md | 74 + docs/true-gold/common/ERC20.md | 166 +++ docs/true-gold/common/ERC20Burnable.md | 28 + docs/true-gold/common/Initializable.md | 21 + docs/true-gold/common/Ownable.md | 46 + docs/true-gold/common/ProxyStorage.md | 8 + docs/true-gold/interface/IOwnable.md | 14 + docs/true-gold/mocks/ERC20Mock.md | 38 + docs/true-gold/mocks/OwnableMock.md | 8 + docs/truefi/ABDKMath64x64.md | 35 + docs/truefi/IChainLink.md | 14 + docs/truefi/Liquidator.md | 66 + docs/truefi/LoanFactory.md | 43 + docs/truefi/LoanToken.md | 276 ++++ docs/truefi/TruPriceChainLinkOracle.md | 37 + docs/truefi/TrueFarm.md | 94 ++ docs/truefi/TrueFiPool.md | 397 ++++++ docs/truefi/TrueLender.md | 276 ++++ docs/truefi/TrueRatingAgency.md | 325 +++++ docs/truefi/TrueRatingAgencyV2.md | 308 +++++ docs/truefi/common/ERC20.md | 208 +++ docs/truefi/common/Initializable.md | 21 + docs/truefi/common/Ownable.md | 55 + .../distributors/ArbitraryDistributor.md | 57 + .../distributors/LinearTrueDistributor.md | 77 ++ .../distributors/RatingAgencyV2Distributor.md | 57 + .../truefi/interface/IArbitraryDistributor.md | 38 + docs/truefi/interface/ICurve.md | 20 + docs/truefi/interface/ICurveGauge.md | 32 + docs/truefi/interface/ICurveMinter.md | 20 + docs/truefi/interface/ICurvePool.md | 44 + docs/truefi/interface/ILoanFactory.md | 20 + docs/truefi/interface/ILoanToken.md | 164 +++ docs/truefi/interface/IMockTruPriceOracle.md | 14 + docs/truefi/interface/IStakingPool.md | 26 + docs/truefi/interface/ITruPriceOracle.md | 20 + docs/truefi/interface/ITrueDistributor.md | 38 + docs/truefi/interface/ITrueFarm.md | 62 + docs/truefi/interface/ITrueFiPool.md | 56 + docs/truefi/interface/ITrueLender.md | 20 + docs/truefi/interface/ITrueRatingAgency.md | 50 + docs/truefi/interface/ITrueRatingAgencyV2.md | 44 + docs/truefi/interface/IUniswapPair.md | 14 + docs/truefi/interface/IUniswapRouter.md | 14 + docs/truefi/interface/IYToken.md | 14 + docs/truefi/mocks/MockCurve.md | 32 + docs/truefi/mocks/MockCurvePool.md | 56 + docs/truefi/mocks/MockLoanFactory.md | 14 + docs/truefi/mocks/MockLog.md | 14 + docs/truefi/mocks/MockStakingPool.md | 26 + docs/truefi/mocks/MockTruPriceOracle.md | 20 + docs/truefi/mocks/MockTrueLender.md | 14 + docs/truefi/mocks/MockYToken.md | 14 + docs/truefi/mocks/PoolArbitrageTest.md | 14 + docs/trusttoken/TimeLockRegistry.md | 58 + docs/trusttoken/TimeLockedToken.md | 131 ++ docs/trusttoken/TrustToken.md | 55 + docs/trusttoken/common/ClaimableContract.md | 60 + docs/trusttoken/common/ERC20.md | 180 +++ docs/trusttoken/common/ProxyStorage.md | 10 + docs/trusttoken/interface/IBurnableERC20.md | 14 + docs/trusttoken/mocks/MockERC20Token.md | 56 + flatten/ArbitraryDistributor.sol | 7 +- flatten/GovernorAlpha.sol | 11 +- flatten/ITruPriceOracle.sol | 4 +- flatten/ITrueRatingAgencyV2.sol | 51 + flatten/LinearTrueDistributor.sol | 1 + flatten/Liquidator.sol | 1228 +++-------------- flatten/LoanFactory.sol | 21 +- flatten/LoanToken.sol | 17 +- flatten/MockLoanFactory.sol | 21 +- flatten/MockOracle.sol | 286 ++++ flatten/MockStakingPool.sol | 5 + flatten/MockTruPriceOracle.sol | 7 +- flatten/MockTrueLender.sol | 30 +- flatten/RatingAgencyV2Distributor.sol | 545 ++++++++ flatten/StkTruToken.sol | 136 +- flatten/TimeLockRegistry.sol | 55 +- flatten/TimeLockedToken.sol | 55 +- flatten/Timelock.sol | 3 +- flatten/TruPriceChainlinkOracle.sol | 252 ++++ flatten/TruPriceUniswapOracle.sol | 286 ++++ flatten/TrueFiPool.sol | 150 +- flatten/TrueLender.sol | 30 +- flatten/TrueRatingAgencyV2.sol | 211 ++- flatten/TrustToken.sol | 55 +- flatten/UpgradeableERC20.sol | 5 + flatten/VoteToken.sol | 55 +- scripts/deploy_truefi.ts | 143 +- test/governance/StkTruToken.test.ts | 4 +- .../distributors/ArbitraryDistributor.test.ts | 4 + 153 files changed, 10881 insertions(+), 1288 deletions(-) create mode 100644 docs/avalanche/AvalancheTokenController.md create mode 100644 docs/avalanche/AvalancheTrueUSD.md create mode 100644 docs/governance/GovernorAlpha.md create mode 100644 docs/governance/StkTruToken.md create mode 100644 docs/governance/Timelock.md create mode 100644 docs/governance/VoteToken.md create mode 100644 docs/governance/common/ClaimableContract.md create mode 100644 docs/governance/interface/ITimelock.md create mode 100644 docs/governance/interface/IVoteToken.md create mode 100644 docs/governance/interface/IVoteTokenWithERC20.md create mode 100644 docs/proxy/OwnedUpgradeabilityProxy.md create mode 100644 docs/proxy/TimeOwnedUpgradeabilityProxy.md create mode 100644 docs/proxy/interface/IOwnedUpgradeabilityProxy.md create mode 100644 docs/registry/Registry.md create mode 100644 docs/registry/interface/IHasOwner.md create mode 100644 docs/registry/interface/IRegistry.md create mode 100644 docs/registry/interface/IRegistryClone.md create mode 100644 docs/registry/mocks/MockRegistrySubscriber.md create mode 100644 docs/registry/mocks/ProvisionalRegistry.md create mode 100644 docs/registry/mocks/ProvisionalRegistryMock.md create mode 100644 docs/registry/mocks/RegistryMock.md create mode 100644 docs/true-currencies/DelegateERC20.md create mode 100644 docs/true-currencies/TokenController.md create mode 100644 docs/true-currencies/TrueCurrency.md create mode 100644 docs/true-currencies/TrueCurrencyWithGasRefund.md create mode 100644 docs/true-currencies/TrueCurrencyWithLegacyAutosweep.md create mode 100644 docs/true-currencies/common/BurnableTokenWithBounds.md create mode 100644 docs/true-currencies/common/ClaimableOwnable.md create mode 100644 docs/true-currencies/common/ERC20.md create mode 100644 docs/true-currencies/common/GasRefund.md create mode 100644 docs/true-currencies/common/ProxyStorage.md create mode 100644 docs/true-currencies/common/ReclaimerToken.md create mode 100644 docs/true-currencies/interface/IHasOwner.md create mode 100644 docs/true-currencies/interface/IHook.md create mode 100644 docs/true-currencies/interface/IReclaimerToken.md create mode 100644 docs/true-currencies/interface/ITrueCurrency.md create mode 100644 docs/true-currencies/mocks/ForceEther.md create mode 100644 docs/true-currencies/mocks/IDelegateERC20.md create mode 100644 docs/true-currencies/mocks/MockDelegateERC20.md create mode 100644 docs/true-currencies/mocks/MockGasRefundToken.md create mode 100644 docs/true-currencies/mocks/MockHook.md create mode 100644 docs/true-currencies/mocks/MockTrueCurrency.md create mode 100644 docs/true-currencies/mocks/MockTrueCurrencyWithAutosweep.md create mode 100644 docs/true-currencies/mocks/MockTrueCurrencyWithDelegate.md create mode 100644 docs/true-currencies/mocks/MockTrueCurrencyWithGasRefund.md create mode 100644 docs/true-currencies/mocks/MockTrueCurrencyWithLegacyAutosweep.md create mode 100644 docs/true-currencies/mocks/TokenControllerMock.md create mode 100644 docs/true-currencies/mocks/TokenControllerPauseMock.md create mode 100644 docs/true-currencies/mocks/TokenFaucet.md create mode 100644 docs/true-currencies/tokens/TrueAUD.md create mode 100644 docs/true-currencies/tokens/TrueCAD.md create mode 100644 docs/true-currencies/tokens/TrueGBP.md create mode 100644 docs/true-currencies/tokens/TrueHKD.md create mode 100644 docs/true-currencies/tokens/TrueUSD.md create mode 100644 docs/true-gold/PausedTrueGold.md create mode 100644 docs/true-gold/Reclaimable.md create mode 100644 docs/true-gold/TrueGold.md create mode 100644 docs/true-gold/TrueGoldController.md create mode 100644 docs/true-gold/TrueMintableBurnable.md create mode 100644 docs/true-gold/common/ERC20.md create mode 100644 docs/true-gold/common/ERC20Burnable.md create mode 100644 docs/true-gold/common/Initializable.md create mode 100644 docs/true-gold/common/Ownable.md create mode 100644 docs/true-gold/common/ProxyStorage.md create mode 100644 docs/true-gold/interface/IOwnable.md create mode 100644 docs/true-gold/mocks/ERC20Mock.md create mode 100644 docs/true-gold/mocks/OwnableMock.md create mode 100644 docs/truefi/ABDKMath64x64.md create mode 100644 docs/truefi/IChainLink.md create mode 100644 docs/truefi/Liquidator.md create mode 100644 docs/truefi/LoanFactory.md create mode 100644 docs/truefi/LoanToken.md create mode 100644 docs/truefi/TruPriceChainLinkOracle.md create mode 100644 docs/truefi/TrueFarm.md create mode 100644 docs/truefi/TrueFiPool.md create mode 100644 docs/truefi/TrueLender.md create mode 100644 docs/truefi/TrueRatingAgency.md create mode 100644 docs/truefi/TrueRatingAgencyV2.md create mode 100644 docs/truefi/common/ERC20.md create mode 100644 docs/truefi/common/Initializable.md create mode 100644 docs/truefi/common/Ownable.md create mode 100644 docs/truefi/distributors/ArbitraryDistributor.md create mode 100644 docs/truefi/distributors/LinearTrueDistributor.md create mode 100644 docs/truefi/distributors/RatingAgencyV2Distributor.md create mode 100644 docs/truefi/interface/IArbitraryDistributor.md create mode 100644 docs/truefi/interface/ICurve.md create mode 100644 docs/truefi/interface/ICurveGauge.md create mode 100644 docs/truefi/interface/ICurveMinter.md create mode 100644 docs/truefi/interface/ICurvePool.md create mode 100644 docs/truefi/interface/ILoanFactory.md create mode 100644 docs/truefi/interface/ILoanToken.md create mode 100644 docs/truefi/interface/IMockTruPriceOracle.md create mode 100644 docs/truefi/interface/IStakingPool.md create mode 100644 docs/truefi/interface/ITruPriceOracle.md create mode 100644 docs/truefi/interface/ITrueDistributor.md create mode 100644 docs/truefi/interface/ITrueFarm.md create mode 100644 docs/truefi/interface/ITrueFiPool.md create mode 100644 docs/truefi/interface/ITrueLender.md create mode 100644 docs/truefi/interface/ITrueRatingAgency.md create mode 100644 docs/truefi/interface/ITrueRatingAgencyV2.md create mode 100644 docs/truefi/interface/IUniswapPair.md create mode 100644 docs/truefi/interface/IUniswapRouter.md create mode 100644 docs/truefi/interface/IYToken.md create mode 100644 docs/truefi/mocks/MockCurve.md create mode 100644 docs/truefi/mocks/MockCurvePool.md create mode 100644 docs/truefi/mocks/MockLoanFactory.md create mode 100644 docs/truefi/mocks/MockLog.md create mode 100644 docs/truefi/mocks/MockStakingPool.md create mode 100644 docs/truefi/mocks/MockTruPriceOracle.md create mode 100644 docs/truefi/mocks/MockTrueLender.md create mode 100644 docs/truefi/mocks/MockYToken.md create mode 100644 docs/truefi/mocks/PoolArbitrageTest.md create mode 100644 docs/trusttoken/TimeLockRegistry.md create mode 100644 docs/trusttoken/TimeLockedToken.md create mode 100644 docs/trusttoken/TrustToken.md create mode 100644 docs/trusttoken/common/ClaimableContract.md create mode 100644 docs/trusttoken/common/ERC20.md create mode 100644 docs/trusttoken/common/ProxyStorage.md create mode 100644 docs/trusttoken/interface/IBurnableERC20.md create mode 100644 docs/trusttoken/mocks/MockERC20Token.md create mode 100644 flatten/ITrueRatingAgencyV2.sol create mode 100644 flatten/RatingAgencyV2Distributor.sol create mode 100644 flatten/TruPriceChainlinkOracle.sol diff --git a/contracts/truefi/LoanFactory.sol b/contracts/truefi/LoanFactory.sol index 56185e411..7d1a77448 100644 --- a/contracts/truefi/LoanFactory.sol +++ b/contracts/truefi/LoanFactory.sol @@ -43,12 +43,14 @@ contract LoanFactory is ILoanFactory, Initializable { currencyToken = _currencyToken; } + /** @dev sets lender address **/ function setLender() external { lender = 0x16d02Dc67EB237C387023339356b25d1D54b0922; } + /** @dev sets liquidator address **/ function setLiquidator() external { - liquidator = address(0); // to be changed for deployment + liquidator = 0x76dd4921C99AC6b61b3a98f9fa6f181cA6D70c77; } /** diff --git a/contracts/truefi/TrueRatingAgencyV2.sol b/contracts/truefi/TrueRatingAgencyV2.sol index 4d58242da..90336da90 100644 --- a/contracts/truefi/TrueRatingAgencyV2.sol +++ b/contracts/truefi/TrueRatingAgencyV2.sol @@ -312,6 +312,11 @@ contract TrueRatingAgencyV2 is ITrueRatingAgencyV2, Ownable { emit Rated(id, msg.sender, choice, stake); } + /** + * @dev Internal function to help reset ratings + * @param id Loan ID + * @param choice Boolean representing choice + */ function _resetCastRatings(address id, bool choice) internal { loans[id].prediction[choice] = loans[id].prediction[choice].sub(loans[id].ratings[msg.sender][choice]); loans[id].ratings[msg.sender][choice] = 0; @@ -319,6 +324,7 @@ contract TrueRatingAgencyV2 is ITrueRatingAgencyV2, Ownable { /** * @dev Cancel ratings of msg.sender + * @param id ID to cancel ratings for */ function resetCastRatings(address id) public onlyPendingLoans(id) { if (getYesRate(id, msg.sender) > 0) { diff --git a/contracts/truefi/distributors/ArbitraryDistributor.sol b/contracts/truefi/distributors/ArbitraryDistributor.sol index ea76cb652..bcced67a5 100644 --- a/contracts/truefi/distributors/ArbitraryDistributor.sol +++ b/contracts/truefi/distributors/ArbitraryDistributor.sol @@ -64,7 +64,12 @@ contract ArbitraryDistributor is IArbitraryDistributor, Ownable { _; } - function setBeneficiaryStatus(address _beneficiary, bool _status) public { + /** + * @dev Set beneficiary status + * @param _beneficiary Contract which can claim TRU + * @param _status Boolean to set whether beneficiary can claim TRU + */ + function setBeneficiaryStatus(address _beneficiary, bool _status) public onlyOwner { beneficiaries[_beneficiary] = _status; emit BeneficiaryStatusChanged(_beneficiary, _status); } diff --git a/contracts/truefi/distributors/RatingAgencyV2Distributor.sol b/contracts/truefi/distributors/RatingAgencyV2Distributor.sol index 09f2f202c..8af79d7ba 100644 --- a/contracts/truefi/distributors/RatingAgencyV2Distributor.sol +++ b/contracts/truefi/distributors/RatingAgencyV2Distributor.sol @@ -40,13 +40,8 @@ contract RatingAgencyV2Distributor is IArbitraryDistributor, Ownable { * @dev Initialize distributor * @param _beneficiary Address for distribution * @param _trustToken TRU address - * @param _amount Amount to distribute */ - function initialize( - address _beneficiary, - IERC20 _trustToken, - uint256 _amount - ) public initializer { + function initialize(address _beneficiary, IERC20 _trustToken) public initializer { Ownable.initialize(); trustToken = _trustToken; beneficiary = _beneficiary; @@ -64,7 +59,12 @@ contract RatingAgencyV2Distributor is IArbitraryDistributor, Ownable { _; } - function setBeneficiaryStatus(address _beneficiary, bool _status) public { + /** + * @dev Owner can set beneficiary status + * @param _beneficiary Contract which can claim TRU + * @param _status Boolean to set whether contract can claim TRU + */ + function setBeneficiaryStatus(address _beneficiary, bool _status) public onlyOwner { beneficiaries[_beneficiary] = _status; emit BeneficiaryStatusChanged(_beneficiary, _status); } diff --git a/docs/avalanche/AvalancheTokenController.md b/docs/avalanche/AvalancheTokenController.md new file mode 100644 index 000000000..5444a15a5 --- /dev/null +++ b/docs/avalanche/AvalancheTokenController.md @@ -0,0 +1,461 @@ +## `AvalancheTokenController` + + + +This contract allows us to split ownership of the TrueCurrency contract +into two addresses. One, called the "owner" address, has unfettered control of the TrueCurrency contract - +it can mint new tokens, transfer ownership of the contract, etc. However to make +extra sure that TrueCurrency is never compromised, this owner key will not be used in +day-to-day operations, allowing it to be stored at a heightened level of security. +Instead, the owner appoints an various "admin" address. +There are 3 different types of admin addresses; MintKey, MintRatifier, and MintPauser. +MintKey can request and revoke mints one at a time. +MintPausers can pause individual mints or pause all mints. +MintRatifiers can approve and finalize mints with enough approval. +There are three levels of mints: instant mint, ratified mint, and multiSig mint. Each have a different threshold +and deduct from a different pool. +Instant mint has the lowest threshold and finalizes instantly without any ratifiers. Deduct from instant mint pool, +which can be refilled by one ratifier. +Ratify mint has the second lowest threshold and finalizes with one ratifier approval. Deduct from ratify mint pool, +which can be refilled by three ratifiers. +MultiSig mint has the highest threshold and finalizes with three ratifier approvals. Deduct from multiSig mint pool, +which can only be refilled by the owner. + +### `onlyMintKeyOrOwner()` + + + + + +### `onlyMintPauserOrOwner()` + + + + + +### `onlyMintRatifierOrOwner()` + + + + + +### `onlyRegistryAdmin()` + + + + + +### `mintNotPaused()` + + + + + +### `onlyOwner()` + + + +Throws if called by any account other than the owner. + +### `onlyPendingOwner()` + + + +Modifier throws if called by any account other than the pendingOwner. + + +### `initialize()` (external) + + + + + +### `transferOwnership(address payable newOwner)` (external) + + + +Allows the current owner to set the pendingOwner address. + + +### `claimOwnership()` (external) + + + +Allows the pendingOwner address to finalize the transfer. + +### `transferTrueCurrencyProxyOwnership(address _newOwner)` (external) + + + + + +### `claimTrueCurrencyProxyOwnership()` (external) + + + + + +### `upgradeTrueCurrencyProxyImplTo(address _implementation)` (external) + + + + + +### `setMintThresholds(uint256 _instant, uint256 _ratified, uint256 _multiSig)` (external) + + + +set the threshold for a mint to be considered an instant mint, +ratify mint and multiSig mint. Instant mint requires no approval, +ratify mint requires 1 approval and multiSig mint requires 3 approvals + +### `setMintLimits(uint256 _instant, uint256 _ratified, uint256 _multiSig)` (external) + + + +set the limit of each mint pool. For example can only instant mint up to the instant mint pool limit +before needing to refill + +### `refillInstantMintPool()` (external) + + + +Ratifier can refill instant mint pool + +### `refillRatifiedMintPool()` (external) + + + +Owner or 3 ratifiers can refill Ratified Mint Pool + +### `refillMultiSigMintPool()` (external) + + + +Owner can refill MultiSig Mint Pool + +### `requestMint(address _to, uint256 _value)` (external) + + + +mintKey initiates a request to mint _value for account _to + + +### `instantMint(address _to, uint256 _value)` (external) + + + +Instant mint without ratification if the amount is less +than instantMintThreshold and instantMintPool + + +### `ratifyMint(uint256 _index, address _to, uint256 _value)` (external) + + + +ratifier ratifies a request mint. If the number of +ratifiers that signed off is greater than the number of +approvals required, the request is finalized + + +### `finalizeMint(uint256 _index)` (public) + + + +finalize a mint request, mint the amount requested to the specified address + + +### `_subtractFromMintPool(uint256 _value)` (internal) + +assumption: only invoked when canFinalize + + + +### `hasEnoughApproval(uint256 _numberOfApproval, uint256 _value) → bool` (public) + + + +compute if the number of approvals is enough for a given mint amount + +### `canFinalize(uint256 _index) → bool` (public) + + + +compute if a mint request meets all the requirements to be finalized +utility function for a front end + +### `revokeMint(uint256 _index)` (external) + + + +revoke a mint request, Delete the mintOperation + + +### `mintOperationCount() → uint256` (public) + + + +get mint operatino count + + +### `transferMintKey(address _newMintKey)` (external) + + + +Replace the current mintkey with new mintkey + + +### `setRegistryAdmin(address admin)` (external) + + + + + +### `setIsMintPauser(address account, bool status)` (external) + + + + + +### `setIsMintRatifier(address account, bool status)` (external) + + + + + +### `invalidateAllPendingMints()` (external) + + + +invalidates all mint request initiated before the current block + +### `pauseMints()` (external) + + + +pause any further mint request and mint finalizations + +### `unpauseMints()` (external) + + + +unpause any further mint request and mint finalizations + +### `pauseMint(uint256 _opIndex)` (external) + + + +pause a specific mint request + + +### `unpauseMint(uint256 _opIndex)` (external) + + + +unpause a specific mint request + + +### `setToken(contract ITrueCurrency _newContract)` (external) + + + +Update this contract's token pointer to newContract (e.g. if the +contract is upgraded) + +### `issueClaimOwnership(address _other)` (public) + + + +Claim ownership of an arbitrary HasOwner contract + +### `transferChild(contract IHasOwner _child, address _newOwner)` (external) + + + +Transfer ownership of _child to _newOwner. +Can be used e.g. to upgrade this TokenController contract. + + +### `requestReclaimEther()` (external) + + + +send all ether in token address to the owner of tokenController + +### `requestReclaimToken(contract IERC20 _token)` (external) + + + +transfer all tokens of a particular type in token address to the +owner of tokenController + + +### `pauseToken()` (external) + + + +pause all pausable actions on TrueCurrency, mints/burn/transfer/approve + +### `setBurnBounds(uint256 _min, uint256 _max)` (external) + + + +Change the minimum and maximum amounts that TrueCurrency users can +burn to newMin and newMax + + +### `reclaimEther(address payable _to)` (external) + + + +Owner can send ether balance in contract address + + +### `reclaimToken(contract IERC20 _token, address _to)` (external) + + + +Owner can send erc20 token balance in contract address + + +### `setCanBurn(address burner, bool canBurn)` (external) + + + +Owner can allow address to burn tokens + + +### `setBlacklisted(address account, bool isBlacklisted)` (external) + + + +Set blacklisted status for the account. + + + +### `OwnershipTransferred(address previousOwner, address newOwner)` + + + +Emitted when ownership of controller was transferred + +### `NewOwnerPending(address currentOwner, address pendingOwner)` + + + +Emitted when ownership of controller transfer procedure was started + +### `TransferChild(address child, address newOwner)` + + + +Emitted when owner was transferred for child contract + +### `RequestReclaimContract(address other)` + + + +Emitted when child ownership was claimed + +### `SetToken(contract ITrueCurrency newContract)` + + + +Emitted when child token was changed + +### `CanBurn(address burner, bool canBurn)` + + + +Emitted when canBurn status of the `burner` was changed to `canBurn` + +### `RequestMint(address to, uint256 value, uint256 opIndex, address mintKey)` + + + +Emitted when mint was requested + +### `FinalizeMint(address to, uint256 value, uint256 opIndex, address mintKey)` + + + +Emitted when mint was finalized + +### `InstantMint(address to, uint256 value, address mintKey)` + + + +Emitted on instant mint + +### `TransferMintKey(address previousMintKey, address newMintKey)` + + + +Emitted when mint key was replaced + +### `MintRatified(uint256 opIndex, address ratifier)` + + + +Emitted when mint was ratified + +### `RevokeMint(uint256 opIndex)` + + + +Emitted when mint is revoked + +### `AllMintsPaused(bool status)` + + + +Emitted when all mining is paused (status=true) or unpaused (status=false) + +### `MintPaused(uint256 opIndex, bool status)` + + + +Emitted when opIndex mint is paused (status=true) or unpaused (status=false) + +### `MintApproved(address approver, uint256 opIndex)` + + + +Emitted when mint is approved + +### `FastPauseSet(address _newFastPause)` + + + +Emitted when fast pause contract is changed + +### `MintThresholdChanged(uint256 instant, uint256 ratified, uint256 multiSig)` + + + +Emitted when mint threshold changes + +### `MintLimitsChanged(uint256 instant, uint256 ratified, uint256 multiSig)` + + + +Emitted when mint limits change + +### `InstantPoolRefilled()` + + + +Emitted when instant mint pool is refilled + +### `RatifyPoolRefilled()` + + + +Emitted when instant mint pool is ratified + +### `MultiSigPoolRefilled()` + + + +Emitted when multisig mint pool is ratified + diff --git a/docs/avalanche/AvalancheTrueUSD.md b/docs/avalanche/AvalancheTrueUSD.md new file mode 100644 index 000000000..6e8e6841a --- /dev/null +++ b/docs/avalanche/AvalancheTrueUSD.md @@ -0,0 +1,39 @@ +## `AvalancheTrueUSD` + + + +This is the top-level ERC20 contract, but most of the interesting functionality is +inherited - see the documentation on the corresponding contracts. + + +### `initialize()` (external) + + + + + +### `decimals() → uint8` (public) + + + + + +### `rounding() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + + diff --git a/docs/governance/GovernorAlpha.md b/docs/governance/GovernorAlpha.md new file mode 100644 index 000000000..d55e2a50c --- /dev/null +++ b/docs/governance/GovernorAlpha.md @@ -0,0 +1,203 @@ +## `GovernorAlpha` + + + + + + +### `quorumVotes() → uint256` (public) + + + + + +### `proposalThreshold() → uint256` (public) + + + + + +### `proposalMaxOperations() → uint256` (public) + + + + + +### `votingDelay() → uint256` (public) + + + + + +### `initialize(contract ITimelock _timelock, contract IVoteToken _trustToken, address _guardian, contract IVoteToken _stkTRU, uint256 _votingPeriod)` (external) + + + +Initialize sets the addresses of timelock contract, trusttoken contract, and guardian + +### `propose(address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, string description) → uint256` (public) + + + +Create a proposal to change the protocol + + +### `queue(uint256 proposalId)` (public) + + + +Queue a proposal after a proposal has succeeded + + +### `_queueOrRevert(address target, uint256 value, string signature, bytes data, uint256 eta)` (internal) + + + +Queue one single proposal transaction to timelock contract + + +### `execute(uint256 proposalId)` (public) + + + +Execute a proposal after a proposal has queued and invoke each of the actions in the proposal + + +### `cancel(uint256 proposalId)` (public) + + + +Cancel a proposal that has not yet been executed + + +### `getActions(uint256 proposalId) → address[] targets, uint256[] values, string[] signatures, bytes[] calldatas` (public) + + + +Get the actions of a selected proposal + + +### `getReceipt(uint256 proposalId, address voter) → struct GovernorAlpha.Receipt` (public) + + + +Get a proposal ballot receipt of the indicated voter + + +### `state(uint256 proposalId) → enum GovernorAlpha.ProposalState` (public) + + + +Get the proposal state for the specified proposal + + +### `castVote(uint256 proposalId, bool support)` (public) + + + +Cast a vote on a proposal + + +### `castVoteBySig(uint256 proposalId, bool support, uint8 v, bytes32 r, bytes32 s)` (public) + + + +Cast a vote on a proposal by offline signatures + + +### `_castVote(address voter, uint256 proposalId, bool support)` (internal) + + + +Cast a vote on a proposal internal function + + +### `__acceptAdmin()` (public) + + + +Accept the pending admin as the admin in timelock contract + +### `__abdicate()` (public) + + + +Abdicate the guardian address to address(0) + +### `__queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta)` (public) + + + +Queue a setTimeLockPendingAdmin transaction to timelock contract + + +### `__executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta)` (public) + + + +Execute a setTimeLockPendingAdmin transaction to timelock contract + + +### `add256(uint256 a, uint256 b) → uint256` (internal) + + + +safe addition function for uint256 + +### `sub256(uint256 a, uint256 b) → uint256` (internal) + + + +safe subtraction function for uint256 + +### `getChainId() → uint256` (internal) + + + +Get the chain ID + + +### `countVotes(address account, uint256 blockNumber) → uint96` (public) + + + +Count the total PriorVotes from TRU and stkTRU + + +### `add96(uint96 a, uint96 b, string errorMessage) → uint96` (internal) + + + + + + +### `ProposalCreated(uint256 id, address proposer, address[] targets, uint256[] values, string[] signatures, bytes[] calldatas, uint256 startBlock, uint256 endBlock, string description)` + + + + + +### `VoteCast(address voter, uint256 proposalId, bool support, uint256 votes)` + + + + + +### `ProposalCanceled(uint256 id)` + + + + + +### `ProposalQueued(uint256 id, uint256 eta)` + + + + + +### `ProposalExecuted(uint256 id)` + + + + + diff --git a/docs/governance/StkTruToken.md b/docs/governance/StkTruToken.md new file mode 100644 index 000000000..5a425aefc --- /dev/null +++ b/docs/governance/StkTruToken.md @@ -0,0 +1,284 @@ +## `StkTruToken` + + + +Staking contract for TrueFi +TRU is staked and stored in the contract +stkTRU is minted when staking +Holders of stkTRU accrue rewards over time +Rewards are paid in TRU and tfUSD +stkTRU can be used to vote in governance +stkTRU can be used to rate and approve loans + +### `onlyLiquidator()` + + + +Only Liquidator contract can perform TRU liquidations + +### `onlyWhitelistedPayers()` + + + +Only whitelisted payers can pay fees + +### `distribute()` + +Get TRU from distributor + + + +### `update(address account)` + +Update all rewards when an account changes state + + + + +### `updateRewards(address account, contract IERC20 token)` + +Update rewards for a specific token when an account changes state + + + + + +### `initialize(contract IERC20 _tru, contract IERC20 _tfusd, contract ITrueDistributor _distributor, address _liquidator)` (public) + + + +Initialize contract and set default values + + +### `setPayerWhitelistingStatus(address payer, bool status)` (external) + + + +Owner can use this function to add new addresses to payers whitelist +Only whitelisted payers can call payFee method + + +### `setCooldownTime(uint256 newCooldownTime)` (external) + + + +Owner can use this function to set cooldown time +Cooldown time defines how long a staker waits to unstake TRU + + +### `setUnstakePeriodDuration(uint256 newUnstakePeriodDuration)` (external) + + + +Owner can set unstake period duration +Unstake period defines how long after cooldown a user has to withdraw stake + + +### `stake(uint256 amount)` (external) + + + +Stake TRU for stkTRU +Updates rewards when staking + + +### `unstake(uint256 amount)` (external) + + + +Unstake stkTRU for TRU +Can only unstake when cooldown complete and within unstake period +Claims rewards when unstaking + + +### `cooldown()` (external) + + + +Initiate cooldown period + +### `withdraw(uint256 amount)` (external) + + + +Withdraw TRU from the contract for liquidation + + +### `unlockTime(address account) → uint256` (public) + + + +View function to get unlock time for an account + + +### `payFee(uint256 amount, uint256 endTime)` (external) + + + +Give tfUSD as origination fee to stake.this +50% are given immediately and 50% after `endTime` passes + +### `claim()` (external) + + + +Claim all rewards + +### `claimRewards(contract IERC20 token)` (external) + + + +Claim rewards for specific token +Allows account to claim specific token to save gas + + +### `claimable(address account, contract IERC20 token) → uint256` (external) + + + +View to estimate the claimable reward for an account + + +### `getPriorVotes(address account, uint256 blockNumber) → uint96` (public) + + + +Prior votes votes are calculated as priorVotes * stakedSupply / totalSupply +This dilutes voting power when TRU is liquidated + + +### `getCurrentVotes(address account) → uint96` (public) + + + +Current votes are calculated as votes * stakedSupply / totalSupply +This dilutes voting power when TRU is liquidated + + +### `decimals() → uint8` (public) + + + + + +### `rounding() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + +### `_transfer(address sender, address recipient, uint256 amount)` (internal) + + + + + +### `_claim(contract IERC20 token)` (internal) + + + +Internal claim function +Claim rewards for a specific ERC20 token + + +### `rewardBalance(contract IERC20 token) → uint256` (internal) + + + +Get reward balance of this contract for a token + + +### `distributeScheduledRewards()` (internal) + + + +Check if any scheduled rewards should be distributed + +### `updateTotalRewards(contract IERC20 token)` (internal) + + + +Update rewards state for `token` + +### `updateClaimableRewards(contract IERC20 token, address user)` (internal) + + + +Update claimable rewards for a token and account + + +### `findPositionForTimestamp(uint256 timestamp) → uint32 i` (internal) + + + +Find next distribution index given a timestamp + + +### `insertAt(uint32 index, uint32 value)` (internal) + + + +internal function to insert distribution index in a sorted list + + + +### `Stake(address staker, uint256 amount)` + + + + + +### `Unstake(address staker, uint256 burntAmount)` + + + + + +### `Claim(address who, contract IERC20 token, uint256 amountClaimed)` + + + + + +### `Withdraw(uint256 amount)` + + + + + +### `Cooldown(address who, uint256 endTime)` + + + + + +### `CooldownTimeChanged(uint256 newUnstakePeriodDuration)` + + + + + +### `UnstakePeriodDurationChanged(uint256 newUnstakePeriodDuration)` + + + + + +### `FeePayerWhitelistingStatusChanged(address payer, bool status)` + + + + + diff --git a/docs/governance/Timelock.md b/docs/governance/Timelock.md new file mode 100644 index 000000000..cece3cf8f --- /dev/null +++ b/docs/governance/Timelock.md @@ -0,0 +1,105 @@ +## `Timelock` + + + + + + +### `initialize(address admin_, uint256 delay_)` (external) + + + +Initialize sets the addresses of admin and the delay timestamp + + +### `receive()` (external) + + + + + +### `setDelay(uint256 delay_)` (public) + + + +Set the timelock delay to a new timestamp + + +### `acceptAdmin()` (public) + + + +Accept the pendingAdmin as the admin address + +### `setPendingAdmin(address pendingAdmin_)` (public) + + + +Set the pendingAdmin address to a new address + + +### `queueTransaction(address target, uint256 value, string signature, bytes data, uint256 eta) → bytes32` (public) + + + +Queue one single proposal transaction + + +### `cancelTransaction(address target, uint256 value, string signature, bytes data, uint256 eta)` (public) + + + +Cancel one single proposal transaction + + +### `executeTransaction(address target, uint256 value, string signature, bytes data, uint256 eta) → bytes` (public) + + + +Execute one single proposal transaction + + +### `getBlockTimestamp() → uint256` (internal) + + + +Get the current block timestamp + + + +### `NewAdmin(address newAdmin)` + + + + + +### `NewPendingAdmin(address newPendingAdmin)` + + + + + +### `NewDelay(uint256 newDelay)` + + + + + +### `CancelTransaction(bytes32 txHash, address target, uint256 value, string signature, bytes data, uint256 eta)` + + + + + +### `ExecuteTransaction(bytes32 txHash, address target, uint256 value, string signature, bytes data, uint256 eta)` + + + + + +### `QueueTransaction(bytes32 txHash, address target, uint256 value, string signature, bytes data, uint256 eta)` + + + + + diff --git a/docs/governance/VoteToken.md b/docs/governance/VoteToken.md new file mode 100644 index 000000000..6c17954a6 --- /dev/null +++ b/docs/governance/VoteToken.md @@ -0,0 +1,123 @@ +## `VoteToken` + +Custom token which tracks voting power for governance + + +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 + + +### `delegate(address delegatee)` (public) + + + + + +### `delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)` (public) + + + +Delegate votes using signature + +### `getCurrentVotes(address account) → uint96` (public) + + + +Get current voting power for an account + + +### `getPriorVotes(address account, uint256 blockNumber) → uint96` (public) + + + +Get voting power at a specific block for an account + + +### `_delegate(address delegator, address delegatee)` (internal) + + + +Internal function to delegate voting power to an account + + +### `_balanceOf(address account) → uint256` (internal) + + + + + +### `_transfer(address _from, address _to, uint256 _value)` (internal) + + + + + +### `_mint(address account, uint256 amount)` (internal) + + + + + +### `_burn(address account, uint256 amount)` (internal) + + + + + +### `_moveDelegates(address srcRep, address dstRep, uint96 amount)` (internal) + + + +internal function to move delegates between accounts + +### `_writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes)` (internal) + + + +internal function to write a checkpoint for voting power + +### `safe32(uint256 n, string errorMessage) → uint32` (internal) + + + +internal function to convert from uint256 to uint32 + +### `safe96(uint256 n, string errorMessage) → uint96` (internal) + + + +internal function to convert from uint256 to uint96 + +### `add96(uint96 a, uint96 b, string errorMessage) → uint96` (internal) + + + +internal safe math function to add two uint96 numbers + +### `sub96(uint96 a, uint96 b, string errorMessage) → uint96` (internal) + + + +internal safe math function to subtract two uint96 numbers + +### `getChainId() → uint256` (internal) + + + +internal function to get chain ID + + +### `DelegateChanged(address delegator, address fromDelegate, address toDelegate)` + + + + + +### `DelegateVotesChanged(address delegate, uint256 previousBalance, uint256 newBalance)` + + + + + diff --git a/docs/governance/common/ClaimableContract.md b/docs/governance/common/ClaimableContract.md new file mode 100644 index 000000000..7ee93b3aa --- /dev/null +++ b/docs/governance/common/ClaimableContract.md @@ -0,0 +1,60 @@ +## `ClaimableContract` + + + +The ClaimableContract contract is a copy of Claimable Contract by Zeppelin. +and provides basic authorization control functions. Inherits storage layout of +ProxyStorage. + +### `onlyOwner()` + + + +Throws if called by any account other than the owner. + +### `onlyPendingOwner()` + + + +Modifier throws if called by any account other than the pendingOwner. + + +### `owner() → address` (public) + + + + + +### `pendingOwner() → address` (public) + + + + + +### `constructor()` (public) + + + +sets the original `owner` of the contract to the sender +at construction. Must then be reinitialized + +### `transferOwnership(address newOwner)` (public) + + + +Allows the current owner to set the pendingOwner address. + + +### `claimOwnership()` (public) + + + +Allows the pendingOwner address to finalize the transfer. + + +### `OwnershipTransferred(address previousOwner, address newOwner)` + + + + + diff --git a/docs/governance/interface/ITimelock.md b/docs/governance/interface/ITimelock.md new file mode 100644 index 000000000..c5b658468 --- /dev/null +++ b/docs/governance/interface/ITimelock.md @@ -0,0 +1,50 @@ +## `ITimelock` + + + + + + +### `delay() → uint256` (external) + + + + + +### `GRACE_PERIOD() → uint256` (external) + + + + + +### `acceptAdmin()` (external) + + + + + +### `queuedTransactions(bytes32 hash) → bool` (external) + + + + + +### `queueTransaction(address target, uint256 value, string signature, bytes data, uint256 eta) → bytes32` (external) + + + + + +### `cancelTransaction(address target, uint256 value, string signature, bytes data, uint256 eta)` (external) + + + + + +### `executeTransaction(address target, uint256 value, string signature, bytes data, uint256 eta) → bytes` (external) + + + + + + diff --git a/docs/governance/interface/IVoteToken.md b/docs/governance/interface/IVoteToken.md new file mode 100644 index 000000000..3dc2bbcf2 --- /dev/null +++ b/docs/governance/interface/IVoteToken.md @@ -0,0 +1,32 @@ +## `IVoteToken` + + + + + + +### `delegate(address delegatee)` (external) + + + + + +### `delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)` (external) + + + + + +### `getCurrentVotes(address account) → uint96` (external) + + + + + +### `getPriorVotes(address account, uint256 blockNumber) → uint96` (external) + + + + + + diff --git a/docs/governance/interface/IVoteTokenWithERC20.md b/docs/governance/interface/IVoteTokenWithERC20.md new file mode 100644 index 000000000..fd4db3ba6 --- /dev/null +++ b/docs/governance/interface/IVoteTokenWithERC20.md @@ -0,0 +1,8 @@ +## `IVoteTokenWithERC20` + + + + + + + diff --git a/docs/proxy/OwnedUpgradeabilityProxy.md b/docs/proxy/OwnedUpgradeabilityProxy.md new file mode 100644 index 000000000..b339a5a80 --- /dev/null +++ b/docs/proxy/OwnedUpgradeabilityProxy.md @@ -0,0 +1,119 @@ +## `OwnedUpgradeabilityProxy` + + + +This contract combines an upgradeability proxy with basic authorization control functionalities + +### `onlyProxyOwner()` + + + +Throws if called by any account other than the owner. + +### `onlyPendingProxyOwner()` + + + +Throws if called by any account other than the pending owner. + + +### `constructor()` (public) + + + +the constructor sets the original owner of the contract to the sender account. + +### `proxyOwner() → address owner` (public) + + + +Tells the address of the owner + + +### `pendingProxyOwner() → address pendingOwner` (public) + + + +Tells the address of the owner + + +### `_setUpgradeabilityOwner(address newProxyOwner)` (internal) + + + +Sets the address of the owner + +### `_setPendingUpgradeabilityOwner(address newPendingProxyOwner)` (internal) + + + +Sets the address of the owner + +### `transferProxyOwnership(address newOwner)` (external) + + + +Allows the current owner to transfer control of the contract to a newOwner. +changes the pending owner to newOwner. But doesn't actually transfer + + +### `claimProxyOwnership()` (external) + + + +Allows the pendingOwner to claim ownership of the proxy + +### `upgradeTo(address implementation)` (public) + + + +Allows the proxy owner to upgrade the current version of the proxy. + + +### `implementation() → address impl` (public) + + + + + +### `fallback()` (external) + + + +Fallback functions allowing to perform a delegatecall to the given implementation. +This function will return whatever the implementation call returns + +### `receive()` (external) + + + + + +### `proxyCall()` (internal) + + + + + + +### `ProxyOwnershipTransferred(address previousOwner, address newOwner)` + + + +Event to show ownership has been transferred + + +### `NewPendingOwner(address currentOwner, address pendingOwner)` + + + +Event to show ownership transfer is pending + + +### `Upgraded(address implementation)` + + + +This event will be emitted every time the implementation gets upgraded + + diff --git a/docs/proxy/TimeOwnedUpgradeabilityProxy.md b/docs/proxy/TimeOwnedUpgradeabilityProxy.md new file mode 100644 index 000000000..e67d383b7 --- /dev/null +++ b/docs/proxy/TimeOwnedUpgradeabilityProxy.md @@ -0,0 +1,42 @@ +## `TimeOwnedUpgradeabilityProxy` + + + +This contract combines an upgradeability proxy with +basic authorization control functionalities +This contract allows us to specify a time at which the proxy can no longer +be upgraded + + +### `constructor()` (public) + + + +the constructor sets the original owner of the contract to the sender account. + +### `setExpiration(uint256 newExpirationTime)` (external) + + + +sets new expiration time + +### `_setExpiration(uint256 newExpirationTime)` (internal) + + + + + +### `expiration() → uint256 _expiration` (public) + + + + + +### `upgradeTo(address implementation)` (public) + + + +Allows the proxy owner to upgrade the current version of the proxy. + + + diff --git a/docs/proxy/interface/IOwnedUpgradeabilityProxy.md b/docs/proxy/interface/IOwnedUpgradeabilityProxy.md new file mode 100644 index 000000000..b43e61941 --- /dev/null +++ b/docs/proxy/interface/IOwnedUpgradeabilityProxy.md @@ -0,0 +1,44 @@ +## `IOwnedUpgradeabilityProxy` + + + + + + +### `proxyOwner() → address owner` (external) + + + + + +### `pendingProxyOwner() → address pendingOwner` (external) + + + + + +### `transferProxyOwnership(address newOwner)` (external) + + + + + +### `claimProxyOwnership()` (external) + + + + + +### `upgradeTo(address implementation)` (external) + + + + + +### `implementation() → address impl` (external) + + + + + + diff --git a/docs/registry/Registry.md b/docs/registry/Registry.md new file mode 100644 index 000000000..668162f49 --- /dev/null +++ b/docs/registry/Registry.md @@ -0,0 +1,147 @@ +## `Registry` + + + + + +### `onlyOwner()` + + + +Throws if called by any account other than the owner. + +### `onlyPendingOwner()` + + + +Modifier throws if called by any account other than the pendingOwner. + + +### `confirmWrite(bytes32 _attribute, address _admin) → bool` (internal) + + + + + +### `setAttribute(address _who, bytes32 _attribute, uint256 _value, bytes32 _notes)` (public) + + + + + +### `subscribe(bytes32 _attribute, contract IRegistryClone _syncer)` (external) + + + + + +### `unsubscribe(bytes32 _attribute, uint256 _index)` (external) + + + + + +### `subscriberCount(bytes32 _attribute) → uint256` (public) + + + + + +### `setAttributeValue(address _who, bytes32 _attribute, uint256 _value)` (public) + + + + + +### `hasAttribute(address _who, bytes32 _attribute) → bool` (public) + + + + + +### `getAttribute(address _who, bytes32 _attribute) → uint256, bytes32, address, uint256` (public) + + + + + +### `getAttributeValue(address _who, bytes32 _attribute) → uint256` (public) + + + + + +### `getAttributeAdminAddr(address _who, bytes32 _attribute) → address` (public) + + + + + +### `getAttributeTimestamp(address _who, bytes32 _attribute) → uint256` (public) + + + + + +### `syncAttribute(bytes32 _attribute, uint256 _startIndex, address[] _addresses)` (external) + + + + + +### `reclaimEther(address payable _to)` (external) + + + + + +### `reclaimToken(contract IERC20 token, address _to)` (external) + + + + + +### `transferOwnership(address newOwner)` (public) + + + +Allows the current owner to set the pendingOwner address. + + +### `claimOwnership()` (public) + + + +Allows the pendingOwner address to finalize the transfer. + + +### `OwnershipTransferred(address previousOwner, address newOwner)` + + + + + +### `SetAttribute(address who, bytes32 attribute, uint256 value, bytes32 notes, address adminAddr)` + + + + + +### `SetManager(address oldManager, address newManager)` + + + + + +### `StartSubscription(bytes32 attribute, contract IRegistryClone subscriber)` + + + + + +### `StopSubscription(bytes32 attribute, contract IRegistryClone subscriber)` + + + + + diff --git a/docs/registry/interface/IHasOwner.md b/docs/registry/interface/IHasOwner.md new file mode 100644 index 000000000..38a1c9fe2 --- /dev/null +++ b/docs/registry/interface/IHasOwner.md @@ -0,0 +1,20 @@ +## `IHasOwner` + + + + + + +### `claimOwnership()` (external) + + + + + +### `transferOwnership(address newOwner)` (external) + + + + + + diff --git a/docs/registry/interface/IRegistry.md b/docs/registry/interface/IRegistry.md new file mode 100644 index 000000000..0ae061b8b --- /dev/null +++ b/docs/registry/interface/IRegistry.md @@ -0,0 +1,74 @@ +## `IRegistry` + + + + + + +### `setAttribute(address _who, bytes32 _attribute, uint256 _value, bytes32 _notes)` (external) + + + + + +### `subscribe(bytes32 _attribute, contract IRegistryClone _syncer)` (external) + + + + + +### `unsubscribe(bytes32 _attribute, uint256 _index)` (external) + + + + + +### `subscriberCount(bytes32 _attribute) → uint256` (external) + + + + + +### `setAttributeValue(address _who, bytes32 _attribute, uint256 _value)` (external) + + + + + +### `hasAttribute(address _who, bytes32 _attribute) → bool` (external) + + + + + +### `getAttribute(address _who, bytes32 _attribute) → uint256, bytes32, address, uint256` (external) + + + + + +### `getAttributeValue(address _who, bytes32 _attribute) → uint256` (external) + + + + + +### `getAttributeAdminAddr(address _who, bytes32 _attribute) → address` (external) + + + + + +### `getAttributeTimestamp(address _who, bytes32 _attribute) → uint256` (external) + + + + + +### `syncAttribute(bytes32 _attribute, uint256 _startIndex, address[] _addresses)` (external) + + + + + + diff --git a/docs/registry/interface/IRegistryClone.md b/docs/registry/interface/IRegistryClone.md new file mode 100644 index 000000000..14cb7f26f --- /dev/null +++ b/docs/registry/interface/IRegistryClone.md @@ -0,0 +1,14 @@ +## `IRegistryClone` + + + + + + +### `syncAttributeValue(address _who, bytes32 _attribute, uint256 _value)` (external) + + + + + + diff --git a/docs/registry/mocks/MockRegistrySubscriber.md b/docs/registry/mocks/MockRegistrySubscriber.md new file mode 100644 index 000000000..a617df346 --- /dev/null +++ b/docs/registry/mocks/MockRegistrySubscriber.md @@ -0,0 +1,20 @@ +## `MockRegistrySubscriber` + + + + + + +### `syncAttributeValue(address _who, bytes32 _attribute, uint256 _value)` (public) + + + + + +### `getAttributeValue(address _who, bytes32 _attribute) → uint256` (public) + + + + + + diff --git a/docs/registry/mocks/ProvisionalRegistry.md b/docs/registry/mocks/ProvisionalRegistry.md new file mode 100644 index 000000000..cb7ecde13 --- /dev/null +++ b/docs/registry/mocks/ProvisionalRegistry.md @@ -0,0 +1,32 @@ +## `ProvisionalRegistry` + + + + + + +### `requireCanTransfer(address _from, address _to) → address, bool` (public) + + + + + +### `requireCanTransferFrom(address _sender, address _from, address _to) → address, bool` (public) + + + + + +### `requireCanMint(address _to) → address, bool` (public) + + + + + +### `requireCanBurn(address _from)` (public) + + + + + + diff --git a/docs/registry/mocks/ProvisionalRegistryMock.md b/docs/registry/mocks/ProvisionalRegistryMock.md new file mode 100644 index 000000000..41cce267e --- /dev/null +++ b/docs/registry/mocks/ProvisionalRegistryMock.md @@ -0,0 +1,8 @@ +## `ProvisionalRegistryMock` + + + + + + + diff --git a/docs/registry/mocks/RegistryMock.md b/docs/registry/mocks/RegistryMock.md new file mode 100644 index 000000000..ca67636c2 --- /dev/null +++ b/docs/registry/mocks/RegistryMock.md @@ -0,0 +1,21 @@ +## `RegistryMock` + + + + + + +### `constructor()` (public) + + + +sets the original `owner` of the contract to the sender +at construction. Must then be reinitialized + +### `initialize()` (public) + + + + + + diff --git a/docs/true-currencies/DelegateERC20.md b/docs/true-currencies/DelegateERC20.md new file mode 100644 index 000000000..d2a9e1232 --- /dev/null +++ b/docs/true-currencies/DelegateERC20.md @@ -0,0 +1,70 @@ +## `DelegateERC20` + + + + + +### `onlyDelegateFrom()` + + + + + + +### `delegateTotalSupply() → uint256` (public) + + + +Delegate call to get total supply + + +### `delegateBalanceOf(address who) → uint256` (public) + + + +Delegate call to get balance + + +### `delegateTransfer(address to, uint256 value, address origSender) → bool` (public) + + + +Delegate call to transfer + + +### `delegateAllowance(address owner, address spender) → uint256` (public) + + + +Delegate call to get allowance + + +### `delegateTransferFrom(address from, address to, uint256 value, address origSender) → bool` (public) + + + +Delegate call to transfer from + + +### `delegateApprove(address spender, uint256 value, address origSender) → bool` (public) + + + +Delegate call to approve + + +### `delegateIncreaseApproval(address spender, uint256 addedValue, address origSender) → bool` (public) + + + +Delegate call to increase approval + + +### `delegateDecreaseApproval(address spender, uint256 subtractedValue, address origSender) → bool` (public) + + + +Delegate call to decrease approval + + + diff --git a/docs/true-currencies/TokenController.md b/docs/true-currencies/TokenController.md new file mode 100644 index 000000000..b134ff410 --- /dev/null +++ b/docs/true-currencies/TokenController.md @@ -0,0 +1,479 @@ +## `TokenController` + + + +This contract allows us to split ownership of the TrueCurrency contract +into two addresses. One, called the "owner" address, has unfettered control of the TrueCurrency contract - +it can mint new tokens, transfer ownership of the contract, etc. However to make +extra sure that TrueCurrency is never compromised, this owner key will not be used in +day-to-day operations, allowing it to be stored at a heightened level of security. +Instead, the owner appoints an various "admin" address. +There are 3 different types of admin addresses; MintKey, MintRatifier, and MintPauser. +MintKey can request and revoke mints one at a time. +MintPausers can pause individual mints or pause all mints. +MintRatifiers can approve and finalize mints with enough approval. +There are three levels of mints: instant mint, ratified mint, and multiSig mint. Each have a different threshold +and deduct from a different pool. +Instant mint has the lowest threshold and finalizes instantly without any ratifiers. Deduct from instant mint pool, +which can be refilled by one ratifier. +Ratify mint has the second lowest threshold and finalizes with one ratifier approval. Deduct from ratify mint pool, +which can be refilled by three ratifiers. +MultiSig mint has the highest threshold and finalizes with three ratifier approvals. Deduct from multiSig mint pool, +which can only be refilled by the owner. + +### `onlyMintKeyOrOwner()` + + + + + +### `onlyMintPauserOrOwner()` + + + + + +### `onlyMintRatifierOrOwner()` + + + + + +### `onlyOwnerOrRedemptionAdmin()` + + + + + +### `onlyGasRefunder()` + + + + + +### `onlyRegistryAdmin()` + + + + + +### `mintNotPaused()` + + + + + +### `onlyOwner()` + + + +Throws if called by any account other than the owner. + +### `onlyPendingOwner()` + + + +Modifier throws if called by any account other than the pendingOwner. + + +### `transferOwnership(address payable newOwner)` (external) + + + +Allows the current owner to set the pendingOwner address. + + +### `claimOwnership()` (external) + + + +Allows the pendingOwner address to finalize the transfer. + +### `transferTrueCurrencyProxyOwnership(address _newOwner)` (external) + + + + + +### `claimTrueCurrencyProxyOwnership()` (external) + + + + + +### `upgradeTrueCurrencyProxyImplTo(address _implementation)` (external) + + + + + +### `setMintThresholds(uint256 _instant, uint256 _ratified, uint256 _multiSig)` (external) + + + +set the threshold for a mint to be considered an instant mint, +ratify mint and multiSig mint. Instant mint requires no approval, +ratify mint requires 1 approval and multiSig mint requires 3 approvals + +### `setMintLimits(uint256 _instant, uint256 _ratified, uint256 _multiSig)` (external) + + + +set the limit of each mint pool. For example can only instant mint up to the instant mint pool limit +before needing to refill + +### `refillInstantMintPool()` (external) + + + +Ratifier can refill instant mint pool + +### `refillRatifiedMintPool()` (external) + + + +Owner or 3 ratifiers can refill Ratified Mint Pool + +### `refillMultiSigMintPool()` (external) + + + +Owner can refill MultiSig Mint Pool + +### `requestMint(address _to, uint256 _value)` (external) + + + +mintKey initiates a request to mint _value for account _to + + +### `instantMint(address _to, uint256 _value)` (external) + + + +Instant mint without ratification if the amount is less +than instantMintThreshold and instantMintPool + + +### `ratifyMint(uint256 _index, address _to, uint256 _value)` (external) + + + +ratifier ratifies a request mint. If the number of +ratifiers that signed off is greater than the number of +approvals required, the request is finalized + + +### `finalizeMint(uint256 _index)` (public) + + + +finalize a mint request, mint the amount requested to the specified address + + +### `_subtractFromMintPool(uint256 _value)` (internal) + +assumption: only invoked when canFinalize + + + +### `hasEnoughApproval(uint256 _numberOfApproval, uint256 _value) → bool` (public) + + + +compute if the number of approvals is enough for a given mint amount + +### `canFinalize(uint256 _index) → bool` (public) + + + +compute if a mint request meets all the requirements to be finalized +utility function for a front end + +### `revokeMint(uint256 _index)` (external) + + + +revoke a mint request, Delete the mintOperation + + +### `mintOperationCount() → uint256` (public) + + + +get mint operatino count + + +### `transferMintKey(address _newMintKey)` (external) + + + +Replace the current mintkey with new mintkey + + +### `setGasRefunder(address refunder)` (external) + + + + + +### `setRegistryAdmin(address admin)` (external) + + + + + +### `invalidateAllPendingMints()` (external) + + + +invalidates all mint request initiated before the current block + +### `pauseMints()` (external) + + + +pause any further mint request and mint finalizations + +### `unpauseMints()` (external) + + + +unpause any further mint request and mint finalizations + +### `pauseMint(uint256 _opIndex)` (external) + + + +pause a specific mint request + + +### `unpauseMint(uint256 _opIndex)` (external) + + + +unpause a specific mint request + + +### `setToken(contract ITrueCurrency _newContract)` (external) + + + +Update this contract's token pointer to newContract (e.g. if the +contract is upgraded) + +### `setRegistry(contract IRegistry _registry)` (external) + + + +Update this contract's registry pointer to _registry + +### `issueClaimOwnership(address _other)` (public) + + + +Claim ownership of an arbitrary HasOwner contract + +### `transferChild(contract IHasOwner _child, address _newOwner)` (external) + + + +Transfer ownership of _child to _newOwner. +Can be used e.g. to upgrade this TokenController contract. + + +### `requestReclaimEther()` (external) + + + +send all ether in token address to the owner of tokenController + +### `requestReclaimToken(contract IERC20 _token)` (external) + + + +transfer all tokens of a particular type in token address to the +owner of tokenController + + +### `pauseToken()` (external) + + + +pause all pausable actions on TrueCurrency, mints/burn/transfer/approve + +### `setBurnBounds(uint256 _min, uint256 _max)` (external) + + + +Change the minimum and maximum amounts that TrueCurrency users can +burn to newMin and newMax + + +### `reclaimEther(address payable _to)` (external) + + + +Owner can send ether balance in contract address + + +### `reclaimToken(contract IERC20 _token, address _to)` (external) + + + +Owner can send erc20 token balance in contract address + + +### `setCanBurn(address burner, bool canBurn)` (external) + + + +Owner can allow address to burn tokens + + +### `setBlacklisted(address account, bool isBlacklisted)` (external) + + + +Set blacklisted status for the account. + + +### `refundGasWithHook(contract IHook hookContract)` (external) + +Call hook in `hookContract` with gas refund + + + + +### `OwnershipTransferred(address previousOwner, address newOwner)` + + + +Emitted when ownership of controller was transferred + +### `NewOwnerPending(address currentOwner, address pendingOwner)` + + + +Emitted when ownership of controller transfer procedure was started + +### `SetRegistry(address registry)` + + + +Emitted when new registry was set + +### `TransferChild(address child, address newOwner)` + + + +Emitted when owner was transferred for child contract + +### `RequestReclaimContract(address other)` + + + +Emitted when child ownership was claimed + +### `SetToken(contract ITrueCurrency newContract)` + + + +Emitted when child token was changed + +### `CanBurn(address burner, bool canBurn)` + + + +Emitted when canBurn status of the `burner` was changed to `canBurn` + +### `RequestMint(address to, uint256 value, uint256 opIndex, address mintKey)` + + + +Emitted when mint was requested + +### `FinalizeMint(address to, uint256 value, uint256 opIndex, address mintKey)` + + + +Emitted when mint was finalized + +### `InstantMint(address to, uint256 value, address mintKey)` + + + +Emitted on instant mint + +### `TransferMintKey(address previousMintKey, address newMintKey)` + + + +Emitted when mint key was replaced + +### `MintRatified(uint256 opIndex, address ratifier)` + + + +Emitted when mint was ratified + +### `RevokeMint(uint256 opIndex)` + + + +Emitted when mint is revoked + +### `AllMintsPaused(bool status)` + + + +Emitted when all mining is paused (status=true) or unpaused (status=false) + +### `MintPaused(uint256 opIndex, bool status)` + + + +Emitted when opIndex mint is paused (status=true) or unpaused (status=false) + +### `MintApproved(address approver, uint256 opIndex)` + + + +Emitted when mint is approved + +### `FastPauseSet(address _newFastPause)` + + + +Emitted when fast pause contract is changed + +### `MintThresholdChanged(uint256 instant, uint256 ratified, uint256 multiSig)` + + + +Emitted when mint threshold changes + +### `MintLimitsChanged(uint256 instant, uint256 ratified, uint256 multiSig)` + + + +Emitted when mint limits change + +### `InstantPoolRefilled()` + + + +Emitted when instant mint pool is refilled + +### `RatifyPoolRefilled()` + + + +Emitted when instant mint pool is ratified + +### `MultiSigPoolRefilled()` + + + +Emitted when multisig mint pool is ratified + diff --git a/docs/true-currencies/TrueCurrency.md b/docs/true-currencies/TrueCurrency.md new file mode 100644 index 000000000..330376d23 --- /dev/null +++ b/docs/true-currencies/TrueCurrency.md @@ -0,0 +1,98 @@ +## `TrueCurrency` + + + +TrueCurrency is an ERC20 with blacklist & redemption addresses +TrueCurrency is a compliant stablecoin with blacklist and redemption +addresses. Only the owner can blacklist accounts. Redemption addresses +are assigned automatically to the first 0x100000 addresses. Sending +tokens to the redemption address will trigger a burn operation. Only +the owner can mint or blacklist accounts. +This contract is owned by the TokenController, which manages token +minting & admin functionality. See TokenController.sol +See also: BurnableTokenWithBounds.sol +~~~~ Features ~~~~ +Redemption Addresses +- The first 0x100000 addresses are redemption addresses +- Tokens sent to redemption addresses are burned +- Redemptions are tracked off-chain +- Cannot mint tokens to redemption addresses +Blacklist +- Owner can blacklist accounts in accordance with local regulatory bodies +- Only a court order will merit a blacklist; blacklisting is extremely rare +Burn Bounds & CanBurn +- Owner can set min & max burn amounts +- Only accounts flagged in canBurn are allowed to burn tokens +- canBurn prevents tokens from being sent to the incorrect address +Reclaimer Token +- ERC20 Tokens and Ether sent to this contract can be reclaimed by the owner + + +### `mint(address account, uint256 amount)` (external) + + + +Creates `amount` tokens and assigns them to `account`, increasing +the total supply. + + +### `setBlacklisted(address account, bool _isBlacklisted)` (external) + + + +Set blacklisted status for the account. + + +### `setCanBurn(address account, bool _canBurn)` (external) + + + +Set canBurn status for the account. + + +### `_transfer(address sender, address recipient, uint256 amount)` (internal) + +Transfer to redemption address will burn tokens with a 1 cent precision + + +Check if neither account is blacklisted before performing transfer +If transfer recipient is a redemption address, burns tokens + + +### `_approve(address owner, address spender, uint256 amount)` (internal) + + + +Requere neither accounts to be blacklisted before approval + + +### `_burn(address account, uint256 amount)` (internal) + + + +Check if tokens can be burned at address before burning + + +### `isRedemptionAddress(address account) → bool` (internal) + +For transfer to succeed, canBurn must be true for redemption address + + +First 0x100000-1 addresses (0x0000000000000000000000000000000000000001 to 0x00000000000000000000000000000000000fffff) +are the redemption addresses. + + + +### `Blacklisted(address account, bool isBlacklisted)` + + + +Emitted when account blacklist status changes + +### `Mint(address to, uint256 value)` + + + +Emitted when `value` tokens are minted for `to` + + diff --git a/docs/true-currencies/TrueCurrencyWithGasRefund.md b/docs/true-currencies/TrueCurrencyWithGasRefund.md new file mode 100644 index 000000000..059bfb40f --- /dev/null +++ b/docs/true-currencies/TrueCurrencyWithGasRefund.md @@ -0,0 +1,16 @@ +## `TrueCurrencyWithGasRefund` + + + + + + +### `refundGas(uint256 amount)` (external) + + + +reclaim gas from legacy gas refund #1 +will refund 15,000 * amount gas to sender (minus exection cost) +If gas pool is empty, refund 39,000 * amount gas by calling selfdestruct + + diff --git a/docs/true-currencies/TrueCurrencyWithLegacyAutosweep.md b/docs/true-currencies/TrueCurrencyWithLegacyAutosweep.md new file mode 100644 index 000000000..7998a42cb --- /dev/null +++ b/docs/true-currencies/TrueCurrencyWithLegacyAutosweep.md @@ -0,0 +1,31 @@ +## `TrueCurrencyWithLegacyAutosweep` + + + +Contract that prevents addresses that were previously using autosweep addresses from +making transfers on them. +In older versions TrueCurrencies had a feature called Autosweep. +Given a single deposit address, it was possible to generate 16^5-1 autosweep addresses. +E.g. having deposit address 0xc257274276a4e539741ca11b590b9447b26a8051, you could generate +- 0xc257274276a4e539741ca11b590b9447b2600000 +- 0xc257274276a4e539741ca11b590b9447b2600001 +- ... +- 0xc257274276a4e539741ca11b590b9447b26fffff +Every transfer to an autosweep address resulted as a transfer to deposit address. +This feature got deprecated, but there were 4 addresses that still actively using the feature. +This contract will reject a transfer to these 4*(16^5-1) addresses to prevent accidental token freeze. + + +### `_transfer(address sender, address recipient, uint256 amount)` (internal) + + + + + +### `requireNotAutosweepAddress(address recipient, address depositAddress)` (internal) + + + + + + diff --git a/docs/true-currencies/common/BurnableTokenWithBounds.md b/docs/true-currencies/common/BurnableTokenWithBounds.md new file mode 100644 index 000000000..a1fd33ad4 --- /dev/null +++ b/docs/true-currencies/common/BurnableTokenWithBounds.md @@ -0,0 +1,53 @@ +## `BurnableTokenWithBounds` + + + +Burning functions as redeeming money from the system. +The platform will keep track of who burns coins, +and will send them back the equivalent amount of money (rounded down to the nearest cent). + + +### `burn(uint256 amount)` (external) + + + +Destroys `amount` tokens from `msg.sender`, reducing the +total supply. + + +### `setBurnBounds(uint256 _min, uint256 _max)` (external) + + + +Change the minimum and maximum amount that can be burned at once. +Burning may be disabled by setting both to 0 (this will not be done +under normal operation, but we can't add checks to disallow it without +losing a lot of flexibility since burning could also be as good as disabled +by setting the minimum extremely high, and we don't want to lock +in any particular cap for the minimum) + + +### `_burn(address account, uint256 amount)` (internal) + + + +Checks if amount is within allowed burn bounds and +destroys `amount` tokens from `account`, reducing the +total supply. + + + +### `Burn(address burner, uint256 value)` + + + +Emitted when `value` tokens are burnt from one account (`burner`) + + +### `SetBurnBounds(uint256 newMin, uint256 newMax)` + +`newMin` should never be greater than `newMax` + +Emitted when new burn bounds were set + + diff --git a/docs/true-currencies/common/ClaimableOwnable.md b/docs/true-currencies/common/ClaimableOwnable.md new file mode 100644 index 000000000..80b890ce8 --- /dev/null +++ b/docs/true-currencies/common/ClaimableOwnable.md @@ -0,0 +1,49 @@ +## `ClaimableOwnable` + + + +The ClamableOwnable contract is a copy of Claimable Contract by Zeppelin. +and provides basic authorization control functions. Inherits storage layout of +ProxyStorage. + +### `onlyOwner()` + + + +Throws if called by any account other than the owner. + +### `onlyPendingOwner()` + + + +Modifier throws if called by any account other than the pendingOwner. + + +### `constructor()` (public) + + + +sets the original `owner` of the contract to the sender +at construction. Must then be reinitialized + +### `transferOwnership(address newOwner)` (public) + + + +Allows the current owner to set the pendingOwner address. + + +### `claimOwnership()` (public) + + + +Allows the pendingOwner address to finalize the transfer. + + +### `OwnershipTransferred(address previousOwner, address newOwner)` + + + +emitted when ownership is transferred + + diff --git a/docs/true-currencies/common/ERC20.md b/docs/true-currencies/common/ERC20.md new file mode 100644 index 000000000..adb85fd99 --- /dev/null +++ b/docs/true-currencies/common/ERC20.md @@ -0,0 +1,183 @@ +## `ERC20` + + + +Implementation of the {IERC20} interface. +This implementation is agnostic to the way tokens are created. This means +that a supply mechanism has to be added in a derived contract using {_mint}. +For a generic mechanism see {ERC20PresetMinterPauser}. +TIP: For a detailed writeup see our guide +https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How +to implement supply mechanisms]. +We have followed general OpenZeppelin guidelines: functions revert instead +of returning `false` on failure. This behavior is nonetheless conventional +and does not conflict with the expectations of ERC20 applications. +Additionally, an {Approval} event is emitted on calls to {transferFrom}. +This allows applications to reconstruct the allowance for all accounts just +by listening to said events. Other implementations of the EIP may not emit +these events, as it isn't required by the specification. +Finally, the non-standard {decreaseAllowance} and {increaseAllowance} +functions have been added to mitigate the well-known issues around setting +allowances. See {IERC20-approve}. + + +### `name() → string` (public) + + + +Returns the name of the token. + +### `symbol() → string` (public) + + + +Returns the symbol of the token, usually a shorter version of the +name. + +### `decimals() → uint8` (public) + + + +Returns the number of decimals used to get its user representation. +For example, if `decimals` equals `2`, a balance of `505` tokens should +be displayed to a user as `5,05` (`505 / 10 ** 2`). +Tokens usually opt for a value of 18, imitating the relationship between +Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is +called. +NOTE: This information is only used for _display_ purposes: it in +no way affects any of the arithmetic of the contract, including +{IERC20-balanceOf} and {IERC20-transfer}. + +### `totalSupply() → uint256` (public) + + + +See {IERC20-totalSupply}. + +### `balanceOf(address account) → uint256` (public) + + + +See {IERC20-balanceOf}. + +### `transfer(address recipient, uint256 amount) → bool` (public) + + + +See {IERC20-transfer}. +Requirements: +- `recipient` cannot be the zero address. +- the caller must have a balance of at least `amount`. + +### `allowance(address owner, address spender) → uint256` (public) + + + +See {IERC20-allowance}. + +### `approve(address spender, uint256 amount) → bool` (public) + + + +See {IERC20-approve}. +Requirements: +- `spender` cannot be the zero address. + +### `transferFrom(address sender, address recipient, uint256 amount) → bool` (public) + + + +See {IERC20-transferFrom}. +Emits an {Approval} event indicating the updated allowance. This is not +required by the EIP. See the note at the beginning of {ERC20}; +Requirements: +- `sender` and `recipient` cannot be the zero address. +- `sender` must have a balance of at least `amount`. +- the caller must have allowance for ``sender``'s tokens of at least +`amount`. + +### `increaseAllowance(address spender, uint256 addedValue) → bool` (public) + + + +Atomically increases the allowance granted to `spender` by the caller. +This is an alternative to {approve} that can be used as a mitigation for +problems described in {IERC20-approve}. +Emits an {Approval} event indicating the updated allowance. +Requirements: +- `spender` cannot be the zero address. + +### `decreaseAllowance(address spender, uint256 subtractedValue) → bool` (public) + + + +Atomically decreases the allowance granted to `spender` by the caller. +This is an alternative to {approve} that can be used as a mitigation for +problems described in {IERC20-approve}. +Emits an {Approval} event indicating the updated allowance. +Requirements: +- `spender` cannot be the zero address. +- `spender` must have allowance for the caller of at least +`subtractedValue`. + +### `_transfer(address sender, address recipient, uint256 amount)` (internal) + + + +Moves tokens `amount` from `sender` to `recipient`. +This is internal function is equivalent to {transfer}, and can be used to +e.g. implement automatic token fees, slashing mechanisms, etc. +Emits a {Transfer} event. +Requirements: +- `sender` cannot be the zero address. +- `recipient` cannot be the zero address. +- `sender` must have a balance of at least `amount`. + +### `_mint(address account, uint256 amount)` (internal) + + + +Creates `amount` tokens and assigns them to `account`, increasing +the total supply. +Emits a {Transfer} event with `from` set to the zero address. +Requirements +- `to` cannot be the zero address. + +### `_burn(address account, uint256 amount)` (internal) + + + +Destroys `amount` tokens from `account`, reducing the +total supply. +Emits a {Transfer} event with `to` set to the zero address. +Requirements +- `account` cannot be the zero address. +- `account` must have at least `amount` tokens. + +### `_approve(address owner, address spender, uint256 amount)` (internal) + + + +Sets `amount` as the allowance of `spender` over the `owner`s tokens. +This is internal function is equivalent to `approve`, and can be used to +e.g. set automatic allowances for certain subsystems, etc. +Emits an {Approval} event. +Requirements: +- `owner` cannot be the zero address. +- `spender` cannot be the zero address. + +### `_beforeTokenTransfer(address from, address to, uint256 amount)` (internal) + + + +Hook that is called before any transfer of tokens. This includes +minting and burning. +Calling conditions: +- when `from` and `to` are both non-zero, `amount` of ``from``'s tokens +will be to transferred to `to`. +- when `from` is zero, `amount` tokens will be minted for `to`. +- when `to` is zero, `amount` of ``from``'s tokens will be burned. +- `from` and `to` are never both zero. +To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + + diff --git a/docs/true-currencies/common/GasRefund.md b/docs/true-currencies/common/GasRefund.md new file mode 100644 index 000000000..9d20526bb --- /dev/null +++ b/docs/true-currencies/common/GasRefund.md @@ -0,0 +1,34 @@ +## `GasRefund` + + + + + + +### `gasRefund15(uint256 amount)` (internal) + + + +Refund 15,000 gas per slot. + + +### `gasRefund39(uint256 amount)` (internal) + + + +use smart contract self-destruct to refund gas +will refund 39,000 * amount gas + +### `remainingGasRefundPool() → uint256 length` (public) + + + +Return the remaining sponsored gas slots + +### `remainingSheepRefundPool() → uint256 length` (public) + + + +Return the remaining sheep slots + + diff --git a/docs/true-currencies/common/ProxyStorage.md b/docs/true-currencies/common/ProxyStorage.md new file mode 100644 index 000000000..604ff0a26 --- /dev/null +++ b/docs/true-currencies/common/ProxyStorage.md @@ -0,0 +1,11 @@ +## `ProxyStorage` + +Defines the storage layout of the token implementation contract. Any +newly declared state variables in future upgrades should be appended +to the bottom. Never remove state variables from this list, however variables +can be renamed. Please add _Deprecated to deprecated variables. + + + + + diff --git a/docs/true-currencies/common/ReclaimerToken.md b/docs/true-currencies/common/ReclaimerToken.md new file mode 100644 index 000000000..37195788c --- /dev/null +++ b/docs/true-currencies/common/ReclaimerToken.md @@ -0,0 +1,24 @@ +## `ReclaimerToken` + + + +ERC20 token which allows owner to reclaim ERC20 tokens +or ether sent to this contract + + +### `reclaimEther(address payable _to)` (external) + + + +send all eth balance in the contract to another address + + +### `reclaimToken(contract IERC20 token, address _to)` (external) + + + +send all token balance of an arbitrary erc20 token +in the contract to another address + + + diff --git a/docs/true-currencies/interface/IHasOwner.md b/docs/true-currencies/interface/IHasOwner.md new file mode 100644 index 000000000..38a1c9fe2 --- /dev/null +++ b/docs/true-currencies/interface/IHasOwner.md @@ -0,0 +1,20 @@ +## `IHasOwner` + + + + + + +### `claimOwnership()` (external) + + + + + +### `transferOwnership(address newOwner)` (external) + + + + + + diff --git a/docs/true-currencies/interface/IHook.md b/docs/true-currencies/interface/IHook.md new file mode 100644 index 000000000..71ce1d24d --- /dev/null +++ b/docs/true-currencies/interface/IHook.md @@ -0,0 +1,14 @@ +## `IHook` + + + + + + +### `hook()` (external) + + + + + + diff --git a/docs/true-currencies/interface/IReclaimerToken.md b/docs/true-currencies/interface/IReclaimerToken.md new file mode 100644 index 000000000..ebe6bc5cd --- /dev/null +++ b/docs/true-currencies/interface/IReclaimerToken.md @@ -0,0 +1,20 @@ +## `IReclaimerToken` + + + + + + +### `reclaimToken(contract IERC20 token, address _to)` (external) + + + + + +### `reclaimEther(address payable _to)` (external) + + + + + + diff --git a/docs/true-currencies/interface/ITrueCurrency.md b/docs/true-currencies/interface/ITrueCurrency.md new file mode 100644 index 000000000..3b500d447 --- /dev/null +++ b/docs/true-currencies/interface/ITrueCurrency.md @@ -0,0 +1,38 @@ +## `ITrueCurrency` + + + + + + +### `refundGas(uint256 amount)` (external) + + + + + +### `setBlacklisted(address account, bool _isBlacklisted)` (external) + + + + + +### `setCanBurn(address account, bool _canBurn)` (external) + + + + + +### `setBurnBounds(uint256 _min, uint256 _max)` (external) + + + + + +### `mint(address account, uint256 amount)` (external) + + + + + + diff --git a/docs/true-currencies/mocks/ForceEther.md b/docs/true-currencies/mocks/ForceEther.md new file mode 100644 index 000000000..12905ef6f --- /dev/null +++ b/docs/true-currencies/mocks/ForceEther.md @@ -0,0 +1,14 @@ +## `ForceEther` + + + + + + +### `destroyAndSend(address _recipient)` (public) + + + + + + diff --git a/docs/true-currencies/mocks/IDelegateERC20.md b/docs/true-currencies/mocks/IDelegateERC20.md new file mode 100644 index 000000000..0f59d4346 --- /dev/null +++ b/docs/true-currencies/mocks/IDelegateERC20.md @@ -0,0 +1,56 @@ +## `IDelegateERC20` + + + + + + +### `delegateTotalSupply() → uint256` (external) + + + + + +### `delegateBalanceOf(address who) → uint256` (external) + + + + + +### `delegateTransfer(address to, uint256 value, address origSender) → bool` (external) + + + + + +### `delegateAllowance(address owner, address spender) → uint256` (external) + + + + + +### `delegateTransferFrom(address from, address to, uint256 value, address origSender) → bool` (external) + + + + + +### `delegateApprove(address spender, uint256 value, address origSender) → bool` (external) + + + + + +### `delegateIncreaseApproval(address spender, uint256 addedValue, address origSender) → bool` (external) + + + + + +### `delegateDecreaseApproval(address spender, uint256 subtractedValue, address origSender) → bool` (external) + + + + + + diff --git a/docs/true-currencies/mocks/MockDelegateERC20.md b/docs/true-currencies/mocks/MockDelegateERC20.md new file mode 100644 index 000000000..571b2ea4b --- /dev/null +++ b/docs/true-currencies/mocks/MockDelegateERC20.md @@ -0,0 +1,81 @@ +## `MockDelegateERC20` + +Mock Legacy TUSD contract. Forwards calls to delegate ERC20 contract + + + + +### `delegateToNewContract(contract IDelegateERC20 newContract)` (public) + + + + + +### `name() → string` (public) + + + +Returns the name of the token. + +### `symbol() → string` (public) + + + +Returns the symbol of the token, usually a shorter version of the +name. + +### `transfer(address to, uint256 value) → bool` (public) + + + + + +### `transferFrom(address from, address to, uint256 value) → bool` (public) + + + + + +### `balanceOf(address who) → uint256` (public) + + + + + +### `approve(address spender, uint256 value) → bool` (public) + + + + + +### `allowance(address _owner, address spender) → uint256` (public) + + + + + +### `totalSupply() → uint256` (public) + + + + + +### `increaseApproval(address spender, uint256 addedValue) → bool` (public) + + + + + +### `decreaseApproval(address spender, uint256 subtractedValue) → bool` (public) + + + + + + +### `DelegatedTo(address newContract)` + + + + + diff --git a/docs/true-currencies/mocks/MockGasRefundToken.md b/docs/true-currencies/mocks/MockGasRefundToken.md new file mode 100644 index 000000000..7f519d2f7 --- /dev/null +++ b/docs/true-currencies/mocks/MockGasRefundToken.md @@ -0,0 +1,20 @@ +## `MockGasRefundToken` + + + + + + +### `sponsorGas(uint256 amount)` (external) + + + + + +### `sponsorGas2(uint256 amount)` (external) + + + + + + diff --git a/docs/true-currencies/mocks/MockHook.md b/docs/true-currencies/mocks/MockHook.md new file mode 100644 index 000000000..d9b7d1990 --- /dev/null +++ b/docs/true-currencies/mocks/MockHook.md @@ -0,0 +1,14 @@ +## `MockHook` + + + + + + +### `hook()` (external) + + + + + + diff --git a/docs/true-currencies/mocks/MockTrueCurrency.md b/docs/true-currencies/mocks/MockTrueCurrency.md new file mode 100644 index 000000000..b13e887b7 --- /dev/null +++ b/docs/true-currencies/mocks/MockTrueCurrency.md @@ -0,0 +1,38 @@ +## `MockTrueCurrency` + + + + + + +### `initialize()` (external) + + + + + +### `decimals() → uint8` (public) + + + + + +### `rounding() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + + diff --git a/docs/true-currencies/mocks/MockTrueCurrencyWithAutosweep.md b/docs/true-currencies/mocks/MockTrueCurrencyWithAutosweep.md new file mode 100644 index 000000000..dab023716 --- /dev/null +++ b/docs/true-currencies/mocks/MockTrueCurrencyWithAutosweep.md @@ -0,0 +1,38 @@ +## `MockTrueCurrencyWithAutosweep` + + + + + + +### `initialize()` (external) + + + + + +### `decimals() → uint8` (public) + + + + + +### `rounding() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + + diff --git a/docs/true-currencies/mocks/MockTrueCurrencyWithDelegate.md b/docs/true-currencies/mocks/MockTrueCurrencyWithDelegate.md new file mode 100644 index 000000000..b5cfeae0c --- /dev/null +++ b/docs/true-currencies/mocks/MockTrueCurrencyWithDelegate.md @@ -0,0 +1,76 @@ +## `MockTrueCurrencyWithDelegate` + + + + + +### `onlyDelegateFrom()` + + + + + + +### `setDelegateAddress(address _delegateFrom)` (external) + + + + + +### `delegateTotalSupply() → uint256` (public) + + + +Delegate call to get total supply + + +### `delegateBalanceOf(address who) → uint256` (public) + + + +Delegate call to get balance + + +### `delegateTransfer(address to, uint256 value, address origSender) → bool` (public) + + + +Delegate call to transfer + + +### `delegateAllowance(address owner, address spender) → uint256` (public) + + + +Delegate call to get allowance + + +### `delegateTransferFrom(address from, address to, uint256 value, address origSender) → bool` (public) + + + +Delegate call to transfer from + + +### `delegateApprove(address spender, uint256 value, address origSender) → bool` (public) + + + +Delegate call to approve + + +### `delegateIncreaseApproval(address spender, uint256 addedValue, address origSender) → bool` (public) + + + +Delegate call to increase approval + + +### `delegateDecreaseApproval(address spender, uint256 subtractedValue, address origSender) → bool` (public) + + + +Delegate call to decrease approval + + + diff --git a/docs/true-currencies/mocks/MockTrueCurrencyWithGasRefund.md b/docs/true-currencies/mocks/MockTrueCurrencyWithGasRefund.md new file mode 100644 index 000000000..8257ca502 --- /dev/null +++ b/docs/true-currencies/mocks/MockTrueCurrencyWithGasRefund.md @@ -0,0 +1,38 @@ +## `MockTrueCurrencyWithGasRefund` + + + + + + +### `initialize()` (external) + + + + + +### `decimals() → uint8` (public) + + + + + +### `rounding() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + + diff --git a/docs/true-currencies/mocks/MockTrueCurrencyWithLegacyAutosweep.md b/docs/true-currencies/mocks/MockTrueCurrencyWithLegacyAutosweep.md new file mode 100644 index 000000000..1b10132bf --- /dev/null +++ b/docs/true-currencies/mocks/MockTrueCurrencyWithLegacyAutosweep.md @@ -0,0 +1,31 @@ +## `MockTrueCurrencyWithLegacyAutosweep` + + + +Contract that prevents addresses that were previously using autosweep addresses from +making transfers on them. +In older versions TrueCurrencies had a feature called Autosweep. +Given a single deposit address, it was possible to generate 16^5-1 autosweep addresses. +E.g. having deposit address 0xc257274276a4e539741ca11b590b9447b26a8051, you could generate +- 0xc257274276a4e539741ca11b590b9447b2600000 +- 0xc257274276a4e539741ca11b590b9447b2600001 +- ... +- 0xc257274276a4e539741ca11b590b9447b26fffff +Every transfer to an autosweep address resulted as a transfer to deposit address. +This feature got deprecated, but there were 4 addresses that still actively using the feature. +This contract will reject a transfer to these 4*(16^5-1) addresses to prevent accidental token freeze. + + +### `_transfer(address sender, address recipient, uint256 amount)` (internal) + + + + + +### `requireNotAutosweepAddress(address recipient, address depositAddress)` (internal) + + + + + + diff --git a/docs/true-currencies/mocks/TokenControllerMock.md b/docs/true-currencies/mocks/TokenControllerMock.md new file mode 100644 index 000000000..3ce030130 --- /dev/null +++ b/docs/true-currencies/mocks/TokenControllerMock.md @@ -0,0 +1,20 @@ +## `TokenControllerMock` + +Token Controller with custom init function for testing + + + + +### `initialize()` (external) + + + + + +### `initializeWithParams(contract ITrueCurrency _token, contract IRegistry _registry)` (external) + + + + + + diff --git a/docs/true-currencies/mocks/TokenControllerPauseMock.md b/docs/true-currencies/mocks/TokenControllerPauseMock.md new file mode 100644 index 000000000..24152425a --- /dev/null +++ b/docs/true-currencies/mocks/TokenControllerPauseMock.md @@ -0,0 +1,20 @@ +## `TokenControllerPauseMock` + + + + + + +### `setPausedImplementation(address _pausedToken)` (external) + + + + + +### `pauseToken()` (external) + + + +pause all pausable actions on TrueUSD, mints/burn/transfer/approve + + diff --git a/docs/true-currencies/mocks/TokenFaucet.md b/docs/true-currencies/mocks/TokenFaucet.md new file mode 100644 index 000000000..06324a906 --- /dev/null +++ b/docs/true-currencies/mocks/TokenFaucet.md @@ -0,0 +1,14 @@ +## `TokenFaucet` + + + + + + +### `faucet(uint256 _amount)` (external) + + + + + + diff --git a/docs/true-currencies/tokens/TrueAUD.md b/docs/true-currencies/tokens/TrueAUD.md new file mode 100644 index 000000000..1ea9537ae --- /dev/null +++ b/docs/true-currencies/tokens/TrueAUD.md @@ -0,0 +1,34 @@ +## `TrueAUD` + +title TrueAUD + + +This is the top-level ERC20 contract, but most of the interesting functionality is +inherited - see the documentation on the corresponding contracts. + + +### `decimals() → uint8` (public) + + + + + +### `rounding() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + + diff --git a/docs/true-currencies/tokens/TrueCAD.md b/docs/true-currencies/tokens/TrueCAD.md new file mode 100644 index 000000000..1335711fe --- /dev/null +++ b/docs/true-currencies/tokens/TrueCAD.md @@ -0,0 +1,33 @@ +## `TrueCAD` + + + +This is the top-level ERC20 contract, but most of the interesting functionality is +inherited - see the documentation on the corresponding contracts. + + +### `decimals() → uint8` (public) + + + + + +### `rounding() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + + diff --git a/docs/true-currencies/tokens/TrueGBP.md b/docs/true-currencies/tokens/TrueGBP.md new file mode 100644 index 000000000..9de6e8184 --- /dev/null +++ b/docs/true-currencies/tokens/TrueGBP.md @@ -0,0 +1,33 @@ +## `TrueGBP` + + + +This is the top-level ERC20 contract, but most of the interesting functionality is +inherited - see the documentation on the corresponding contracts. + + +### `decimals() → uint8` (public) + + + + + +### `rounding() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + + diff --git a/docs/true-currencies/tokens/TrueHKD.md b/docs/true-currencies/tokens/TrueHKD.md new file mode 100644 index 000000000..35e3d7d9f --- /dev/null +++ b/docs/true-currencies/tokens/TrueHKD.md @@ -0,0 +1,33 @@ +## `TrueHKD` + + + +This is the top-level ERC20 contract, but most of the interesting functionality is +inherited - see the documentation on the corresponding contracts. + + +### `decimals() → uint8` (public) + + + + + +### `rounding() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + + diff --git a/docs/true-currencies/tokens/TrueUSD.md b/docs/true-currencies/tokens/TrueUSD.md new file mode 100644 index 000000000..59f0d32af --- /dev/null +++ b/docs/true-currencies/tokens/TrueUSD.md @@ -0,0 +1,33 @@ +## `TrueUSD` + + + +This is the top-level ERC20 contract, but most of the interesting functionality is +inherited - see the documentation on the corresponding contracts. + + +### `decimals() → uint8` (public) + + + + + +### `rounding() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + + diff --git a/docs/true-gold/PausedTrueGold.md b/docs/true-gold/PausedTrueGold.md new file mode 100644 index 000000000..4cd06ae00 --- /dev/null +++ b/docs/true-gold/PausedTrueGold.md @@ -0,0 +1,56 @@ +## `PausedTrueGold` + + + + + + +### `transfer(address, uint256) → bool` (public) + + + + + +### `transferFrom(address, address, uint256) → bool` (public) + + + + + +### `burn(uint256)` (public) + + + + + +### `burnFrom(address, uint256)` (public) + + + + + +### `mint(address, uint256)` (public) + + + + + +### `approve(address, uint256) → bool` (public) + + + + + +### `increaseAllowance(address, uint256) → bool` (public) + + + + + +### `decreaseAllowance(address, uint256) → bool` (public) + + + + + + diff --git a/docs/true-gold/Reclaimable.md b/docs/true-gold/Reclaimable.md new file mode 100644 index 000000000..39aaee4de --- /dev/null +++ b/docs/true-gold/Reclaimable.md @@ -0,0 +1,26 @@ +## `Reclaimable` + + + + + + +### `reclaimEther(address payable to)` (public) + + + + + +### `reclaimToken(contract IERC20 token, address to)` (public) + + + + + +### `reclaimContract(contract IOwnable ownable)` (public) + + + + + + diff --git a/docs/true-gold/TrueGold.md b/docs/true-gold/TrueGold.md new file mode 100644 index 000000000..e37b29f0e --- /dev/null +++ b/docs/true-gold/TrueGold.md @@ -0,0 +1,44 @@ +## `TrueGold` + + + + + + +### `initialize(uint256 minBurnAmount, uint256 maxBurnAmount)` (public) + + + + + +### `decimals() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + +### `setBurnBounds(uint256 minAmount, uint256 maxAmount)` (public) + + + + + +### `_burn(address account, uint256 amount)` (internal) + + + + + + diff --git a/docs/true-gold/TrueGoldController.md b/docs/true-gold/TrueGoldController.md new file mode 100644 index 000000000..bd894365d --- /dev/null +++ b/docs/true-gold/TrueGoldController.md @@ -0,0 +1,435 @@ +## `TrueGoldController` + + + +This contract has been copied from {true-currencies} repository and adjusted for TrueGold needs. +https://github.com/trusttoken/true-currencies/blob/eb01ca47111e66c9fa8bf59d78617ad28e232e06/contracts/truecurrencies/admin/TokenController.sol +This contract allows us to split ownership of the TrueGold contract +into two addresses. One, called the "owner" address, has unfettered control of the TrueGold contract - +it can mint new tokens, transfer ownership of the contract, etc. However to make +extra sure that TrueGold is never compromised, this owner key will not be used in +day-to-day operations, allowing it to be stored at a heightened level of security. +Instead, the owner appoints an various "admin" address. +There are 3 different types of admin addresses; MintKey, MintRatifier, and MintPauser. +MintKey can request and revoke mints one at a time. +MintPausers can pause individual mints or pause all mints. +MintRatifiers can approve and finalize mints with enough approval. +There are three levels of mints: instant mint, ratified mint, and multiSig mint. Each have a different threshold +and deduct from a different pool. +Instant mint has the lowest threshold and finalizes instantly without any ratifiers. Deduct from instant mint pool, +which can be refilled by one ratifier. +Ratify mint has the second lowest threshold and finalizes with one ratifier approval. Deduct from ratify mint pool, +which can be refilled by three ratifiers. +MultiSig mint has the highest threshold and finalizes with three ratifier approvals. Deduct from multiSig mint pool, +which can only be refilled by the owner. + +### `onlyFastPauseOrOwner()` + + + + + +### `onlyMintKeyOrOwner()` + + + + + +### `onlyMintPauserOrOwner()` + + + + + +### `onlyMintRatifierOrOwner()` + + + + + +### `mintNotPaused()` + + + + + +### `onlyOwner()` + + + +Throws if called by any account other than the owner. + +### `onlyPendingOwner()` + + + +Modifier throws if called by any account other than the pendingOwner. + + +### `initialize()` (external) + + + + + +### `transferOwnership(address payable newOwner)` (external) + + + +Allows the current owner to set the pendingOwner address. + + +### `claimOwnership()` (external) + + + +Allows the pendingOwner address to finalize the transfer. + +### `transferTokenProxyOwnership(address _newOwner)` (external) + + + + + +### `claimTokenProxyOwnership()` (external) + + + + + +### `upgradeTokenProxyImplTo(address _implementation)` (external) + + + + + +### `setMintThresholds(uint256 _instant, uint256 _ratified, uint256 _multiSig)` (external) + + + +set the threshold for a mint to be considered an instant mint, ratify mint and multiSig mint +Instant mint requires no approval, ratify mint requires 1 approval and multiSig mint requires 3 approvals + +### `setMintLimits(uint256 _instant, uint256 _ratified, uint256 _multiSig)` (external) + + + +set the limit of each mint pool. For example can only instant mint up to the instant mint pool limit +before needing to refill + +### `refillInstantMintPool()` (external) + + + +Ratifier can refill instant mint pool + +### `refillRatifiedMintPool()` (external) + + + +Owner or 3 ratifiers can refill Ratified Mint Pool + +### `refillMultiSigMintPool()` (external) + + + +Owner can refill MultiSig Mint Pool + +### `requestMint(address _to, uint256 _value)` (external) + + + +mintKey initiates a request to mint _value for account _to + + +### `instantMint(address _to, uint256 _value)` (external) + + + +Instant mint without ratification if the amount is less than instantMintThreshold and instantMintPool + + +### `ratifyMint(uint256 _index, address _to, uint256 _value)` (external) + + + +ratifier ratifies a request mint. If the number of ratifiers that signed off is greater than +the number of approvals required, the request is finalized + + +### `finalizeMint(uint256 _index)` (public) + + + +finalize a mint request, mint the amount requested to the specified address + + +### `_subtractFromMintPool(uint256 _value)` (internal) + +assumption: only invoked when canFinalize + + + +### `hasEnoughApproval(uint256 _numberOfApproval, uint256 _value) → bool` (public) + + + +compute if the number of approvals is enough for a given mint amount + +### `canFinalize(uint256 _index) → bool` (public) + + + +compute if a mint request meets all the requirements to be finalized +utility function for a front end + +### `revokeMint(uint256 _index)` (external) + + + +revoke a mint request, Delete the mintOperation + + +### `mintOperationCount() → uint256` (public) + + + + + +### `transferMintKey(address _newMintKey)` (external) + + + +Replace the current mintkey with new mintkey + + +### `invalidateAllPendingMints()` (external) + + + +invalidates all mint request initiated before the current block + +### `pauseMints()` (external) + + + +pause any further mint request and mint finalizations + +### `unpauseMints()` (external) + + + +unpause any further mint request and mint finalizations + +### `pauseMint(uint256 _opIndex)` (external) + + + +pause a specific mint request + + +### `unpauseMint(uint256 _opIndex)` (external) + + + +unpause a specific mint request + + +### `setToken(contract TrueGold _newContract)` (external) + + + +Update this contract's token pointer to newContract (e.g. if the +contract is upgraded) + +### `setRegistry(contract Registry _registry)` (external) + + + +Update this contract's registry pointer to _registry + +### `transferChild(contract IOwnable _child, address _newOwner)` (external) + + + +Transfer ownership of _child to _newOwner. +Can be used e.g. to upgrade this TrueGoldController contract. + + +### `requestReclaimContract(contract IOwnable _other)` (public) + + + +Transfer ownership of a contract from token to this TrueGoldController. + + +### `requestReclaimEther()` (external) + + + +send all ether in token address to the owner of TrueGoldController + +### `requestReclaimToken(contract IERC20 _token)` (external) + + + +transfer all tokens of a particular type in token address to the +owner of TrueGoldController + + +### `setFastPause(address _newFastPause)` (external) + + + +set new contract to which specified address can send eth to to quickly pause token + + +### `pauseToken()` (external) + + + +pause all pausable actions on TrueGold, mints/burn/transfer/approve + +### `setBurnBounds(uint256 _min, uint256 _max)` (external) + + + +Change the minimum and maximum amounts that TrueGold users can +burn to newMin and newMax + + +### `reclaimEther(address payable _to)` (external) + + + +Owner can send ether balance in contract address + + +### `reclaimToken(contract IERC20 _token, address _to)` (external) + + + +Owner can send erc20 token balance in contract address + + + +### `OwnershipTransferred(address previousOwner, address newOwner)` + + + + + +### `NewOwnerPending(address currentOwner, address pendingOwner)` + + + + + +### `SetRegistry(address registry)` + + + + + +### `TransferChild(address child, address newOwner)` + + + + + +### `ReclaimContract(address other)` + + + + + +### `SetToken(contract TrueGold newContract)` + + + + + +### `RequestMint(address to, uint256 value, uint256 opIndex, address mintKey)` + + + + + +### `FinalizeMint(address to, uint256 value, uint256 opIndex, address mintKey)` + + + + + +### `InstantMint(address to, uint256 value, address mintKey)` + + + + + +### `TransferMintKey(address previousMintKey, address newMintKey)` + + + + + +### `MintRatified(uint256 opIndex, address ratifier)` + + + + + +### `RevokeMint(uint256 opIndex)` + + + + + +### `AllMintsPaused(bool status)` + + + + + +### `MintPaused(uint256 opIndex, bool status)` + + + + + +### `FastPauseSet(address _newFastPause)` + + + + + +### `MintThresholdChanged(uint256 instant, uint256 ratified, uint256 multiSig)` + + + + + +### `MintLimitsChanged(uint256 instant, uint256 ratified, uint256 multiSig)` + + + + + +### `InstantPoolRefilled()` + + + + + +### `RatifyPoolRefilled()` + + + + + +### `MultiSigPoolRefilled()` + + + + + diff --git a/docs/true-gold/TrueMintableBurnable.md b/docs/true-gold/TrueMintableBurnable.md new file mode 100644 index 000000000..b21f03622 --- /dev/null +++ b/docs/true-gold/TrueMintableBurnable.md @@ -0,0 +1,74 @@ +## `TrueMintableBurnable` + + + + + + +### `__TrueMintableBurnable_init_unchained(uint256 minBurnAmount, uint256 maxBurnAmount)` (internal) + + + + + +### `burnMin() → uint256` (public) + + + + + +### `burnMax() → uint256` (public) + + + + + +### `setBurnBounds(uint256 minAmount, uint256 maxAmount)` (public) + + + + + +### `mint(address account, uint256 amount)` (public) + + + + + +### `transfer(address recipient, uint256 amount) → bool` (public) + + + + + +### `transferFrom(address sender, address recipient, uint256 amount) → bool` (public) + + + + + +### `_burn(address account, uint256 amount)` (internal) + + + + + + +### `Mint(address to, uint256 value)` + + + + + +### `Burn(address burner, uint256 value)` + + + + + +### `SetBurnBounds(uint256 newMin, uint256 newMax)` + + + + + diff --git a/docs/true-gold/common/ERC20.md b/docs/true-gold/common/ERC20.md new file mode 100644 index 000000000..0ce6c3b23 --- /dev/null +++ b/docs/true-gold/common/ERC20.md @@ -0,0 +1,166 @@ +## `ERC20` + + + +Implementation of the {IERC20} interface. +This implementation is agnostic to the way tokens are created. This means +that a supply mechanism has to be added in a derived contract using {_mint}. +For a generic mechanism see {ERC20MinterPauser}. +TIP: For a detailed writeup see our guide +https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How +to implement supply mechanisms]. +We have followed general OpenZeppelin guidelines: functions revert instead +of returning `false` on failure. This behavior is nonetheless conventional +and does not conflict with the expectations of ERC20 applications. +Additionally, an {Approval} event is emitted on calls to {transferFrom}. +This allows applications to reconstruct the allowance for all accounts just +by listening to said events. Other implementations of the EIP may not emit +these events, as it isn't required by the specification. +Finally, the non-standard {decreaseAllowance} and {increaseAllowance} +functions have been added to mitigate the well-known issues around setting +allowances. See {IERC20-approve}. + + +### `name() → string` (public) + + + +Returns the name of the token. + +### `symbol() → string` (public) + + + +Returns the symbol of the token, usually a shorter version of the +name. + +### `decimals() → uint8` (public) + + + +Returns the number of decimals used to get its user representation. +For example, if `decimals` equals `2`, a balance of `505` tokens should +be displayed to a user as `5,05` (`505 / 10 ** 2`). +NOTE: This information is only used for _display_ purposes: it in +no way affects any of the arithmetic of the contract, including +{IERC20-balanceOf} and {IERC20-transfer}. + +### `totalSupply() → uint256` (public) + + + +See {IERC20-totalSupply}. + +### `balanceOf(address account) → uint256` (public) + + + +See {IERC20-balanceOf}. + +### `transfer(address recipient, uint256 amount) → bool` (public) + + + +See {IERC20-transfer}. +Requirements: +- `recipient` cannot be the zero address. +- the caller must have a balance of at least `amount`. + +### `allowance(address owner, address spender) → uint256` (public) + + + +See {IERC20-allowance}. + +### `approve(address spender, uint256 amount) → bool` (public) + + + +See {IERC20-approve}. +Requirements: +- `spender` cannot be the zero address. + +### `transferFrom(address sender, address recipient, uint256 amount) → bool` (public) + + + +See {IERC20-transferFrom}. +Emits an {Approval} event indicating the updated allowance. This is not +required by the EIP. See the note at the beginning of {ERC20}; +Requirements: +- `sender` and `recipient` cannot be the zero address. +- `sender` must have a balance of at least `amount`. +- the caller must have allowance for ``sender``'s tokens of at least +`amount`. + +### `increaseAllowance(address spender, uint256 addedValue) → bool` (public) + + + +Atomically increases the allowance granted to `spender` by the caller. +This is an alternative to {approve} that can be used as a mitigation for +problems described in {IERC20-approve}. +Emits an {Approval} event indicating the updated allowance. +Requirements: +- `spender` cannot be the zero address. + +### `decreaseAllowance(address spender, uint256 subtractedValue) → bool` (public) + + + +Atomically decreases the allowance granted to `spender` by the caller. +This is an alternative to {approve} that can be used as a mitigation for +problems described in {IERC20-approve}. +Emits an {Approval} event indicating the updated allowance. +Requirements: +- `spender` cannot be the zero address. +- `spender` must have allowance for the caller of at least +`subtractedValue`. + +### `_transfer(address sender, address recipient, uint256 amount)` (internal) + + + +Moves tokens `amount` from `sender` to `recipient`. +This is internal function is equivalent to {transfer}, and can be used to +e.g. implement automatic token fees, slashing mechanisms, etc. +Emits a {Transfer} event. +Requirements: +- `sender` cannot be the zero address. +- `recipient` cannot be the zero address. +- `sender` must have a balance of at least `amount`. + +### `_mint(address account, uint256 amount)` (internal) + + + +Creates `amount` tokens and assigns them to `account`, increasing +the total supply. +Emits a {Transfer} event with `from` set to the zero address. +Requirements +- `to` cannot be the zero address. + +### `_burn(address account, uint256 amount)` (internal) + + + +Destroys `amount` tokens from `account`, reducing the +total supply. +Emits a {Transfer} event with `to` set to the zero address. +Requirements +- `account` cannot be the zero address. +- `account` must have at least `amount` tokens. + +### `_approve(address owner, address spender, uint256 amount)` (internal) + + + +Sets `amount` as the allowance of `spender` over the `owner`s tokens. +This is internal function is equivalent to `approve`, and can be used to +e.g. set automatic allowances for certain subsystems, etc. +Emits an {Approval} event. +Requirements: +- `owner` cannot be the zero address. +- `spender` cannot be the zero address. + + diff --git a/docs/true-gold/common/ERC20Burnable.md b/docs/true-gold/common/ERC20Burnable.md new file mode 100644 index 000000000..2c12dbceb --- /dev/null +++ b/docs/true-gold/common/ERC20Burnable.md @@ -0,0 +1,28 @@ +## `ERC20Burnable` + + + +Extension of {ERC20} that allows token holders to destroy both their own +tokens and those that they have an allowance for, in a way that can be +recognized off-chain (via event analysis). + + +### `burn(uint256 amount)` (public) + + + +Destroys `amount` tokens from the caller. +See {ERC20-_burn}. + +### `burnFrom(address account, uint256 amount)` (public) + + + +Destroys `amount` tokens from `account`, deducting from the caller's +allowance. +See {ERC20-_burn} and {ERC20-allowance}. +Requirements: +- the caller must have allowance for ``accounts``'s tokens of at least +`amount`. + + diff --git a/docs/true-gold/common/Initializable.md b/docs/true-gold/common/Initializable.md new file mode 100644 index 000000000..622130da0 --- /dev/null +++ b/docs/true-gold/common/Initializable.md @@ -0,0 +1,21 @@ +## `Initializable` + + + +Helper contract to support initializer functions. To use it, replace +the constructor with a function that has the `initializer` modifier. +WARNING: Unlike constructors, initializer functions must be manually +invoked. This applies both to deploying an Initializable contract, as well +as extending an Initializable contract via inheritance. +WARNING: When used with inheritance, manual care must be taken to not invoke +a parent initializer twice, or ensure that all initializers are idempotent, +because this is not dealt with automatically as with constructors. + +### `initializer()` + + + +Modifier to use in the initializer function of a contract. + + + diff --git a/docs/true-gold/common/Ownable.md b/docs/true-gold/common/Ownable.md new file mode 100644 index 000000000..824191fa8 --- /dev/null +++ b/docs/true-gold/common/Ownable.md @@ -0,0 +1,46 @@ +## `Ownable` + + + +Contract module which provides a basic access control mechanism, where +there is an account (an owner) that can be granted exclusive access to +specific functions. +By default, the owner account will be the one that deploys the contract. This +can later be changed with {transferOwnership}. +This module is used through inheritance. It will make available the modifier +`onlyOwner`, which can be applied to your functions to restrict their use to +the owner. + +### `onlyOwner()` + + + +Throws if called by any account other than the owner. + + +### `__Ownable_init_unchained()` (internal) + + + +Initializes the contract setting the deployer as the initial owner. + +### `owner() → address` (public) + + + +Returns the address of the current owner. + +### `transferOwnership(address newOwner)` (public) + + + +Transfers ownership of the contract to a new account (`newOwner`). +Can only be called by the current owner. + + +### `OwnershipTransferred(address previousOwner, address newOwner)` + + + + + diff --git a/docs/true-gold/common/ProxyStorage.md b/docs/true-gold/common/ProxyStorage.md new file mode 100644 index 000000000..00fccc1dc --- /dev/null +++ b/docs/true-gold/common/ProxyStorage.md @@ -0,0 +1,8 @@ +## `ProxyStorage` + + + + + + + diff --git a/docs/true-gold/interface/IOwnable.md b/docs/true-gold/interface/IOwnable.md new file mode 100644 index 000000000..97122f986 --- /dev/null +++ b/docs/true-gold/interface/IOwnable.md @@ -0,0 +1,14 @@ +## `IOwnable` + + + + + + +### `transferOwnership(address newOwner)` (external) + + + + + + diff --git a/docs/true-gold/mocks/ERC20Mock.md b/docs/true-gold/mocks/ERC20Mock.md new file mode 100644 index 000000000..738793f85 --- /dev/null +++ b/docs/true-gold/mocks/ERC20Mock.md @@ -0,0 +1,38 @@ +## `ERC20Mock` + + + + + + +### `constructor(address initialAccount, uint256 initialBalance)` (public) + + + + + +### `mint(address account, uint256 amount)` (public) + + + + + +### `burn(address account, uint256 amount)` (public) + + + + + +### `transferInternal(address from, address to, uint256 value)` (public) + + + + + +### `approveInternal(address owner, address spender, uint256 value)` (public) + + + + + + diff --git a/docs/true-gold/mocks/OwnableMock.md b/docs/true-gold/mocks/OwnableMock.md new file mode 100644 index 000000000..a1d26cf03 --- /dev/null +++ b/docs/true-gold/mocks/OwnableMock.md @@ -0,0 +1,8 @@ +## `OwnableMock` + + + + + + + diff --git a/docs/truefi/ABDKMath64x64.md b/docs/truefi/ABDKMath64x64.md new file mode 100644 index 000000000..555be5042 --- /dev/null +++ b/docs/truefi/ABDKMath64x64.md @@ -0,0 +1,35 @@ +## `ABDKMath64x64` + +Smart contract library of mathematical functions operating with signed +64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is +basically a simple fraction whose numerator is signed 128-bit integer and +denominator is 2^64. As long as denominator is always the same, there is no +need to store it, thus in Solidity signed 64.64-bit fixed point numbers are +represented by int128 type holding only the numerator. + + + + +### `fromUInt(uint256 x) → int128` (internal) + +Convert unsigned 256-bit integer number into signed 64.64-bit fixed point +number. Revert on overflow. + + + + +### `log_2(int128 x) → int128` (internal) + +Calculate binary logarithm of x. Revert if x <= 0. + + + + +### `ln(int128 x) → int128` (internal) + +Calculate natural logarithm of x. Revert if x <= 0. + + + + + diff --git a/docs/truefi/IChainLink.md b/docs/truefi/IChainLink.md new file mode 100644 index 000000000..bad912ef5 --- /dev/null +++ b/docs/truefi/IChainLink.md @@ -0,0 +1,14 @@ +## `IChainLink` + + + + + + +### `latestAnswer() → int256` (external) + + + + + + diff --git a/docs/truefi/Liquidator.md b/docs/truefi/Liquidator.md new file mode 100644 index 000000000..f84f86bb6 --- /dev/null +++ b/docs/truefi/Liquidator.md @@ -0,0 +1,66 @@ +## `Liquidator` + +Liquidate LoanTokens with this Contract + + +When a Loan becomes defaulted, Liquidator allows to +compensate pool participants, by transfering some of TRU to the pool + + +### `initialize(contract ITrueFiPool _pool, contract IStakingPool _stkTru, contract IERC20 _tru, contract ITruPriceOracle _oracle, contract ILoanFactory _factory)` (public) + + + +Initialize this contract + +### `setFetchMaxShare(uint256 newShare)` (external) + + + +Set new max fetch share + + +### `setOracle(contract ITruPriceOracle newOracle)` (external) + + + +Change oracle + + +### `liquidate(contract ILoanToken loan)` (external) + + + +Liquidates a defaulted Loan, withdraws a portion of tru from staking pool +then transfers tru to TrueFiPool as compensation + + +### `getAmountToWithdraw(uint256 deficit) → uint256` (internal) + + + +Calculate amount of tru to be withdrawn from staking pool (not more than preset share) + + + +### `FetchMaxShareChanged(uint256 newShare)` + + + +Emitted fetch max share is changed + + +### `OracleChanged(contract ITruPriceOracle newOracle)` + + + +Emitted when oracle is changed + + +### `Liquidated(contract ILoanToken loan)` + + + +Emitted when a loan gets liquidated + + diff --git a/docs/truefi/LoanFactory.md b/docs/truefi/LoanFactory.md new file mode 100644 index 000000000..c4d70d906 --- /dev/null +++ b/docs/truefi/LoanFactory.md @@ -0,0 +1,43 @@ +## `LoanFactory` + +Deploy LoanTokens with this Contract + + +LoanTokens are deployed through a factory to ensure that all +LoanTokens adhere to the same contract code, rather than using an interface. + + +### `initialize(contract IERC20 _currencyToken)` (external) + + + +Initialize this contract and set currency token + + +### `setLender()` (external) + + + +sets lender address * + +### `setLiquidator()` (external) + + + +sets liquidator address * + +### `createLoanToken(uint256 _amount, uint256 _term, uint256 _apy)` (external) + + + +Deploy LoanToken with parameters + + + +### `LoanTokenCreated(address contractAddress)` + + + +Emitted when a LoanToken is created + + diff --git a/docs/truefi/LoanToken.md b/docs/truefi/LoanToken.md new file mode 100644 index 000000000..48036943d --- /dev/null +++ b/docs/truefi/LoanToken.md @@ -0,0 +1,276 @@ +## `LoanToken` + + + +A token which represents share of a debt obligation +Each LoanToken has: +- borrower address +- borrow amount +- loan term +- loan APY +Loan progresses through the following states: +Awaiting: Waiting for funding to meet capital requirements +Funded: Capital requirements met, borrower can withdraw +Withdrawn: Borrower withdraws money, loan waiting to be repaid +Settled: Loan has been paid back in full with interest +Defaulted: Loan has not been paid back in full +Liquidated: Loan has Defaulted and stakers have been Liquidated +- LoanTokens are non-transferable except for whitelisted addresses +- This version of LoanToken only supports a single funder + +### `onlyBorrower()` + + + +Only borrower can withdraw & repay loan + +### `onlyLiquidator()` + + + +Only liquidator can liquidate + +### `onlyClosed()` + + + +Only when loan is Settled + +### `onlyOngoing()` + + + +Only when loan is Funded + +### `onlyFunded()` + + + +Only when loan is Funded + +### `onlyAfterWithdraw()` + + + +Only when loan is Withdrawn + +### `onlyAwaiting()` + + + +Only when loan is Awaiting + +### `onlyDefaulted()` + + + +Only when loan is Defaulted + +### `onlyWhoCanTransfer(address sender)` + + + +Only whitelisted accounts or lender + +### `onlyLender()` + + + +Only lender can perform certain actions + + +### `constructor(contract IERC20 _currencyToken, address _borrower, address _lender, address _liquidator, uint256 _amount, uint256 _term, uint256 _apy)` (public) + + + +Create a Loan + + +### `isLoanToken() → bool` (external) + + + +Return true if this contract is a LoanToken + + +### `getParameters() → uint256, uint256, uint256` (external) + + + +Get loan parameters + + +### `value(uint256 _balance) → uint256` (external) + + + +Get coupon value of this loan token in currencyToken +This assumes the loan will be paid back on time, with interest + + +### `fund()` (external) + + + +Fund a loan +Set status, start time, lender + +### `allowTransfer(address account, bool _status)` (external) + + + +Whitelist accounts to transfer + + +### `withdraw(address _beneficiary)` (external) + + + +Borrower calls this function to withdraw funds +Sets the status of the loan to Withdrawn + + +### `close()` (external) + + + +Close the loan and check if it has been repaid + +### `liquidate()` (external) + + + +Liquidate the loan if it has defaulted + +### `redeem(uint256 _amount)` (external) + + + +Redeem LoanToken balances for underlying currencyToken +Can only call this function after the loan is Closed + + +### `repay(address _sender, uint256 _amount)` (external) + + + +Function for borrower to repay the loan +Borrower can repay at any time + + +### `reclaim()` (external) + + + +Function for borrower to reclaim stuck currencyToken +Can only call this function after the loan is Closed +and all of LoanToken holders have been burnt + +### `repaid() → uint256` (external) + + + +Check how much was already repaid +Funds stored on the contract's address plus funds already redeemed by lenders + + +### `balance() → uint256` (external) + + + +Public currency token balance function + + +### `_balance() → uint256` (internal) + + + +Get currency token balance for this contract + + +### `receivedAmount() → uint256` (public) + + + +Calculate amount borrowed minus fee + + +### `interest(uint256 _amount) → uint256` (internal) + + + +Calculate interest that will be paid by this loan for an amount (returned funds included) +amount + ((amount * apy * term) / (365 days / precision)) + + +### `profit() → uint256` (external) + + + +get profit for this loan + + +### `_transfer(address sender, address recipient, uint256 _amount)` (internal) + + + +Override ERC20 _transfer so only whitelisted addresses can transfer + + + +### `Funded(address lender)` + + + +Emitted when the loan is funded + + +### `TransferAllowanceChanged(address account, bool status)` + + + +Emitted when transfer whitelist is updated + + +### `Withdrawn(address beneficiary)` + + + +Emitted when borrower withdraws funds + + +### `Closed(enum ILoanToken.Status status, uint256 returnedAmount)` + + + +Emitted when term is over + + +### `Redeemed(address receiver, uint256 burnedAmount, uint256 redeemedAmount)` + + + +Emitted when a LoanToken is redeemed for underlying currencyTokens + + +### `Repaid(address repayer, uint256 repaidAmount)` + + + +Emitted when a LoanToken is repaid by the borrower in underlying currencyTokens + + +### `Reclaimed(address borrower, uint256 reclaimedAmount)` + + + +Emitted when borrower reclaims remaining currencyTokens + + +### `Liquidated(enum ILoanToken.Status status)` + + + +Emitted when loan gets liquidated + + diff --git a/docs/truefi/TruPriceChainLinkOracle.md b/docs/truefi/TruPriceChainLinkOracle.md new file mode 100644 index 000000000..c94237c8e --- /dev/null +++ b/docs/truefi/TruPriceChainLinkOracle.md @@ -0,0 +1,37 @@ +## `TruPriceChainLinkOracle` + + + + + + +### `constructor(contract IChainLink _chainlinkOracle)` (public) + + + + + +### `usdToTru(uint256 amount) → uint256` (external) + + + +converts from USD with 18 decimals to TRU with 8 decimals +Divide by 100 since Chainlink returns 10 decimals and TRU is 8 decimals + + +### `truToUsd(uint256 amount) → uint256` (external) + + + +converts from TRU with 8 decimals to USD with 18 decimals +Multiply by 100 since Chainlink returns 10 decimals and TRU is 8 decimals + + +### `safeUint(int256 value) → uint256` (internal) + + + +convert int256 to uint256 + + + diff --git a/docs/truefi/TrueFarm.md b/docs/truefi/TrueFarm.md new file mode 100644 index 000000000..75e613e50 --- /dev/null +++ b/docs/truefi/TrueFarm.md @@ -0,0 +1,94 @@ +## `TrueFarm` + +Deposit liquidity tokens to earn TRU rewards over time + + +Staking pool where tokens are staked for TRU rewards +A Distributor contract decides how much TRU a farm can earn over time + +### `update()` + + + +Update state and get TRU from distributor + + +### `initialize(contract IERC20 _stakingToken, contract ITrueDistributor _trueDistributor, string _name)` (public) + + + +Initalize staking pool with a Distributor contract +The distributor contract calculates how much TRU rewards this contract +gets, and stores TRU for distribution. + + +### `stake(uint256 amount)` (external) + + + +Stake tokens for TRU rewards. +Also claims any existing rewards. + + +### `_unstake(uint256 amount)` (internal) + + + +Internal unstake function + + +### `_claim()` (internal) + + + +Internal claim function + +### `unstake(uint256 amount)` (external) + + + +Remove staked tokens + + +### `claim()` (external) + + + +Claim TRU rewards + +### `exit(uint256 amount)` (external) + + + +Unstake amount and claim rewards + + +### `claimable(address account) → uint256` (external) + + + +View to estimate the claimable reward for an account + + + +### `Stake(address who, uint256 amountStaked)` + + + +Emitted when an account stakes + + +### `Unstake(address who, uint256 amountUnstaked)` + + + +Emitted when an account unstakes + + +### `Claim(address who, uint256 amountClaimed)` + + + +Emitted when an account claims TRU rewards + + diff --git a/docs/truefi/TrueFiPool.md b/docs/truefi/TrueFiPool.md new file mode 100644 index 000000000..5b5761239 --- /dev/null +++ b/docs/truefi/TrueFiPool.md @@ -0,0 +1,397 @@ +## `TrueFiPool` + + + +Lending pool which uses curve.fi to store idle funds +Earn high interest rates on currency deposits through uncollateralized loans +Funds deposited in this pool are not fully liquid. Luqidity +Exiting the pool has 2 options: +- withdraw a basket of LoanTokens backing the pool +- take an exit penallty depending on pool liquidity +After exiting, an account will need to wait for LoanTokens to expire and burn them +It is recommended to perform a zap or swap tokens on Uniswap for increased liquidity +Funds are managed through an external function to save gas on deposits + +### `onlyLender()` + + + +only lender can perform borrowing or repaying + +### `joiningNotPaused()` + + + +pool can only be joined when it's unpaused + +### `onlyOwnerOrManager()` + + + +only lender can perform borrowing or repaying + +### `sync()` + +Sync values to avoid making expensive calls multiple times +Will set inSync to true, allowing getter functions to return cached values +Wipes cached values to save gas + + + + +### `initialize(contract ICurvePool __curvePool, contract ICurveGauge __curveGauge, contract IERC20 __currencyToken, contract ITrueLender __lender, contract IUniswapRouter __uniRouter, contract IERC20 __stakeToken, contract ITruPriceOracle __oracle)` (public) + + + +Initialize pool + + +### `currencyToken() → contract IERC20` (public) + + + +get currency token address + + +### `stakeToken() → contract IERC20` (public) + + + +get stake token address + + +### `setStakeToken(contract IERC20 token)` (public) + + + +set stake token address + + +### `setFundsManager(address newFundsManager)` (public) + + + +set funds manager address + +### `setOracle(contract ITruPriceOracle newOracle)` (public) + + + +set oracle token address + + +### `changeJoiningPauseStatus(bool status)` (external) + + + +Allow pausing of deposits in case of emergency + + +### `stakeTokenBalance() → uint256` (public) + + + +Get total balance of stake tokens + + +### `yTokenBalance() → uint256` (public) + + + +Get total balance of curve.fi pool tokens + + +### `yTokenValue() → uint256` (public) + + + +Virtual value of yCRV tokens in the pool +Will return sync value if inSync + + +### `truValue() → uint256` (public) + + + +Price of TRU in USD + + +### `liquidValue() → uint256` (public) + + + +Virtual value of liquid assets in the pool + + +### `poolValue() → uint256` (public) + + + +Calculate pool value in TUSD +"virtual price" of entire pool - LoanTokens, TUSD, curve y pool tokens + + +### `loansValue() → uint256` (public) + + + +Virtual value of loan assets in the pool +Will return cached value if inSync + + +### `ensureEnoughTokensAreAvailable(uint256 neededAmount)` (internal) + + + +ensure enough curve.fi pool tokens are available +Check if current available amount of TUSD is enough and +withdraw remainder from gauge + + +### `setJoiningFee(uint256 fee)` (external) + + + +set pool join fee + + +### `resetApprovals()` (external) + + + +sets all token allowances used to 0 + +### `join(uint256 amount)` (external) + + + +Join the pool by depositing currency tokens + + +### `exit(uint256 amount)` (external) + + + +Exit pool +This function will withdraw a basket of currencies backing the pool value + + +### `liquidExit(uint256 amount)` (external) + + + +Exit pool only with liquid tokens +This function will withdraw TUSD but with a small penalty +Uses the sync() modifier to reduce gas costs of using curve + + +### `liquidExitPenalty(uint256 amount) → uint256` (public) + + + +Penalty (in % * 100) applied if liquid exit is performed with this amount +returns 10000 if no penalty + +### `integrateAtPoint(uint256 x) → uint256` (public) + + + +Calculates integral of 5/(x+50)dx times 10000 + +### `averageExitPenalty(uint256 from, uint256 to) → uint256` (public) + + + +Calculates average penalty on interval [from; to] + + +### `flush(uint256 currencyAmount, uint256 minMintAmount)` (external) + + + +Deposit idle funds into curve.fi pool and stake in gauge +Called by owner to help manage funds in pool and save on gas for deposits + + +### `pull(uint256 yAmount, uint256 minCurrencyAmount)` (external) + + + +Remove liquidity from curve + + +### `borrow(uint256 amount, uint256 fee)` (external) + + + +Remove liquidity from curve if necessary and transfer to lender + + +### `removeLiquidityFromCurve(uint256 amountToWithdraw)` (internal) + + + + + +### `repay(uint256 currencyAmount)` (external) + + + +repay debt by transferring tokens to the contract + + +### `collectCrv()` (external) + + + +Collect CRV tokens minted by staking at gauge + +### `sellCrv(uint256 amountIn, uint256 amountOutMin, address[] path)` (public) + + + +Sell collected CRV on Uniswap +- Selling CRV is managed by the contract owner +- Calculations can be made off-chain and called based on market conditions +- Need to pass path of exact pairs to go through while executing exchange +For example, CRV -> WETH -> TUSD + + +### `sellStakeToken(uint256 amountIn, uint256 amountOutMin, address[] path)` (public) + + + +Sell collected TRU on Uniswap +- Selling TRU is managed by the contract owner +- Calculations can be made off-chain and called based on market conditions +- Need to pass path of exact pairs to go through while executing exchange +For example, CRV -> WETH -> TUSD + + +### `collectFees(address beneficiary)` (external) + + + +Claim fees from the pool + + +### `calcTokenAmount(uint256 currencyAmount) → uint256` (public) + +Expected amount of minted Curve.fi yDAI/yUSDC/yUSDT/yTUSD tokens. +Can be used to control slippage +Called in flush() function + + + + +### `calcWithdrawOneCoin(uint256 yAmount) → uint256` (public) + + + +Converts the value of a single yCRV into an underlying asset + + +### `currencyBalance() → uint256` (internal) + + + +Currency token balance + + +### `mint(uint256 depositedAmount) → uint256` (internal) + + + + + +### `updateNameAndSymbol()` (public) + + + +Update name and symbol of this contract + + +### `StakeTokenChanged(contract IERC20 token)` + + + +Emitted when stake token address + + +### `OracleChanged(contract ITruPriceOracle newOracle)` + + + +Emitted oracle was changed + + +### `FundsManagerChanged(address newManager)` + + + +Emitted when funds manager is changed + + +### `JoiningFeeChanged(uint256 newFee)` + + + +Emitted when fee is changed + + +### `Joined(address staker, uint256 deposited, uint256 minted)` + + + +Emitted when someone joins the pool + + +### `Exited(address staker, uint256 amount)` + + + +Emitted when someone exits the pool + + +### `Flushed(uint256 currencyAmount)` + + + +Emitted when funds are flushed into curve.fi + + +### `Pulled(uint256 yAmount)` + + + +Emitted when funds are pulled from curve.fi + + +### `Borrow(address borrower, uint256 amount, uint256 fee)` + + + +Emitted when funds are borrowed from pool + + +### `Repaid(address payer, uint256 amount)` + + + +Emitted when borrower repays the pool + + +### `Collected(address beneficiary, uint256 amount)` + + + +Emitted when fees are collected + + +### `JoiningPauseStatusChanged(bool isJoiningPaused)` + + + +Emitted when joining is paused or unpaused + + diff --git a/docs/truefi/TrueLender.md b/docs/truefi/TrueLender.md new file mode 100644 index 000000000..ad9f7ae32 --- /dev/null +++ b/docs/truefi/TrueLender.md @@ -0,0 +1,276 @@ +## `TrueLender` + + + +TrueFi Lending Strategy +This contract implements the lending strategy for the TrueFi pool +The strategy takes into account several parameters and consumes +information from the prediction market in order to approve loans +This strategy is conservative to avoid defaults. +See: https://github.com/trusttoken/truefi-spec +1. Only approve loans which have the following inherent properties: +- minAPY <= loanAPY <= maxAPY +- minSize <= loanSize <= maxSize +- minTerm <= loanTerm <= maxTerm +2. Only approve loans which have been rated in the prediction market under the conditions: +- timeInMarket >= votingPeriod +- stakedTRU > (participationFactor * loanSize) +- 1 < ( interest * P(loan_repaid) - (loanSize * riskAversion * P(loan_defaults)) +Once a loan meets these requirements, fund() can be called to transfer +funds from the pool to the LoanToken contract + +### `onlyPool()` + + + +Modifier for only lending pool + + +### `initialize(contract ITrueFiPool _pool, contract ITrueRatingAgency _ratingAgency, contract IStakingPool _stakingPool)` (public) + + + +Initalize the contract with parameters + + +### `setStakingPool(contract IStakingPool newPool)` (public) + + + +set stake pool address + + +### `setSizeLimits(uint256 min, uint256 max)` (external) + + + +Set new bounds on loan size. Only owner can change parameters. + + +### `setTermLimits(uint256 min, uint256 max)` (external) + + + +Set new bounds on loan term length. Only owner can change parameters. + + +### `setApyLimits(uint256 newMinApy, uint256 newMaxApy)` (external) + + + +Set new bounds on loan APY. Only owner can change parameters. + + +### `setVotingPeriod(uint256 newVotingPeriod)` (external) + + + +Set new minimum voting period in credit rating market. +Only owner can change parameters + + +### `setParticipationFactor(uint256 newParticipationFactor)` (external) + + + +Set new participation factor. Only owner can change parameters. + + +### `setRiskAversion(uint256 newRiskAversion)` (external) + + + +Set new risk aversion factor. Only owner can change parameters. + + +### `setLoansLimit(uint256 newLoansLimit)` (external) + + + +Set new loans limit. Only owner can change parameters. + + +### `setRatingAgency(contract ITrueRatingAgency newRatingAgency)` (external) + + + +Set new rating agency. Only owner can change parameters. + + +### `loans() → contract ILoanToken[] result` (public) + + + +Get currently funded loans + + +### `fund(contract ILoanToken loanToken)` (external) + + + +Fund a loan which meets the strategy requirements + + +### `loanValue(contract ILoanToken loan) → uint256` (public) + + + +Temporary fix for old LoanTokens with incorrect value calculation + + +### `value() → uint256` (external) + + + +Loop through loan tokens and calculate theoretical value of all loans +There should never be too many loans in the pool to run out of gas + + +### `reclaim(contract ILoanToken loanToken)` (external) + + + +For settled loans, redeem LoanTokens for underlying funds + + +### `distribute(address recipient, uint256 numerator, uint256 denominator)` (external) + + + +Withdraw a basket of tokens held by the pool +When exiting the pool, the pool contract calls this function +to withdraw a fraction of all the loans held by the pool +Loop through recipient's share of LoanTokens and calculate versus total per loan. +There should never be too many loans in the pool to run out of gas + + +### `loanIsAttractiveEnough(uint256 apy) → bool` (public) + + + +Check if a loan is within APY bounds + + +### `votingLastedLongEnough(uint256 start) → bool` (public) + + + +Check if a loan has been in the credit market long enough + + +### `loanSizeWithinBounds(uint256 amount) → bool` (public) + + + +Check if a loan is within size bounds + + +### `loanTermWithinBounds(uint256 term) → bool` (public) + + + +Check if loan term is within term bounds + + +### `votesThresholdReached(uint256 amount, uint256 yesVotes) → bool` (public) + + + +Check if a loan is within APY bounds +Minimum absolute value of yes votes, rather than ratio of yes to no + + +### `loanIsCredible(uint256 apy, uint256 term, uint256 yesVotes, uint256 noVotes) → bool` (public) + + + +Use APY and term of loan to check expected value of a loan +Expected value = profit - (default_loss * (no / yes)) +e.g. riskAversion = 10,000 => expected value of 1 + + + +### `Allowed(address who, bool status)` + + + +Emitted when a borrower's whitelist status changes + + +### `ApyLimitsChanged(uint256 minApy, uint256 maxApy)` + + + +Emitted when APY bounds have changed + + +### `ParticipationFactorChanged(uint256 participationFactor)` + + + +Emitted when participation factor changed + + +### `RiskAversionChanged(uint256 riskAversion)` + + + +Emitted when risk aversion changed + + +### `VotingPeriodChanged(uint256 votingPeriod)` + + + +Emitted when the minimum voting period is changed + + +### `SizeLimitsChanged(uint256 minSize, uint256 maxSize)` + + + +Emitted when the loan size bounds are changed + + +### `TermLimitsChanged(uint256 minTerm, uint256 maxTerm)` + + + +Emitted when loan term bounds are changed + + +### `LoansLimitChanged(uint256 maxLoans)` + + + +Emitted when loans limit is changed + + +### `StakingPoolChanged(contract IStakingPool pool)` + + + +Emitted when stakingPool address is changed + + +### `Funded(address loanToken, uint256 amount)` + + + +Emitted when a loan is funded + + +### `Reclaimed(address loanToken, uint256 amount)` + + + +Emitted when funds are reclaimed from the LoanToken contract + + +### `RatingAgencyChanged(address newRatingAgency)` + + + +Emitted when rating agency contract is changed + + diff --git a/docs/truefi/TrueRatingAgency.md b/docs/truefi/TrueRatingAgency.md new file mode 100644 index 000000000..9b8f35124 --- /dev/null +++ b/docs/truefi/TrueRatingAgency.md @@ -0,0 +1,325 @@ +## `TrueRatingAgency` + + + +Credit prediction market for LoanTokens +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 TRU holder can vote YES or NO and stake TRU as collateral on their vote. +If a loan is funded, TRU is locked into the market until expiry. +Locking TRU into the prediction market allows voters to earn and claim +incentive TRU throughout the course of the loan. After the loan's term, +if the voter is correct, they earn a TRU reward plus a portion of the +losing side's vote. A portion of the losing side's TRU is burned. +Voting Lifecycle: +- Borrowers can apply for loans at any time by deploying a LoanToken +- LoanTokens are registered with the prediction market contract +- Once registered, TRU holders can vote at any time +- If a loan is funded, TRU is locked for the term of the loan +- At the end of the term, payouts are determined based on the loan outcome +States: +Void: Rated loan is invalid +Pending: Waiting to be funded +Retracted: Rating has been cancelled +Running: Rated loan has been funded +Settled: Rated loan has been paid back in full +Defaulted: Rated loan has not been paid back in full + +### `onlyAllowedSubmitters()` + + + +Only whitelisted borrowers can submit for credit ratings + +### `onlyCreator(address id)` + + + +Only loan submitter can perform certain actions + +### `onlyNotExistingLoans(address id)` + + + +Cannot submit the same loan multiple times + +### `onlyPendingLoans(address id)` + + + +Only loans in Pending state + +### `onlyNotRunningLoans(address id)` + + + +Only loans in Running state + +### `onlyFundedLoans(address id)` + + + +Only loans that have been funded + +### `calculateTotalReward(address id)` + + + +Update total TRU reward for a Loan +Reward is divided proportionally based on # TRU staked +chi = (TRU remaining in distributor) / (Total TRU allocated for distribution) +interest = (loan APY * term * principal) +R = Total Reward = (interest * chi * rewardFactor) + + + +### `initialize(contract IBurnableERC20 _trustToken, contract IArbitraryDistributor _distributor, contract ILoanFactory _factory)` (public) + + + +Initalize Rating Agenct +Distributor contract decides how much TRU is rewarded to stakers + + +### `setLossFactor(uint256 newLossFactor)` (external) + + + +Set loss factor. +Loss factor decides what percentage of TRU is lost for incorrect votes + + +### `setBurnFactor(uint256 newBurnFactor)` (external) + + + +Set burn factor. +Burn factor decides what percentage of lost TRU is burned + +### `setRewardMultiplier(uint256 newRewardMultiplier)` (external) + + + +Set reward multiplier. +Reward multiplier increases reward for TRU stakers + +### `getNoVote(address id, address voter) → uint256` (public) + + + +Get number of NO votes for a specific account and loan + + +### `getYesVote(address id, address voter) → uint256` (public) + + + +Get number of YES votes for a specific account and loan + + +### `getTotalNoVotes(address id) → uint256` (public) + + + +Get total NO votes for a specific loan + + +### `getTotalYesVotes(address id) → uint256` (public) + + + +Get total YES votes for a specific loan + + +### `getVotingStart(address id) → uint256` (public) + + + +Get timestamp at which voting started for a specific loan + + +### `getResults(address id) → uint256, uint256, uint256` (external) + + + +Get current results for a specific loan + + +### `allow(address who, bool status)` (external) + + + +Whitelist borrowers to submit loans for rating + + +### `pauseSubmissions(bool status)` (public) + + + +Pause submitting loans for rating + + +### `submit(address id)` (external) + + + +Submit a loan for rating +Cannot submit the same loan twice + + +### `retract(address id)` (external) + + + +Remove Loan from rating agency +Can only be retracted by loan creator + + +### `vote(address id, uint256 stake, bool choice)` (internal) + + + +Vote on a loan by staking TRU + + +### `yes(address id, uint256 stake)` (external) + + + +Vote YES on a loan by staking TRU + + +### `no(address id, uint256 stake)` (external) + + + +Vote NO on a loan by staking TRU + + +### `withdraw(address id, uint256 stake)` (external) + + + +Withdraw stake on a loan and remove votes. +Unstaking only allowed for loans that are not Running + + +### `bounty(address id, bool incorrectChoice) → uint256` (public) + + + +Total amount of funds given to correct voters + + +### `toTrustToken(uint256 input) → uint256 output` (internal) + + + +Internal view to convert values to 8 decimals precision + + +### `claim(address id, address voter)` (public) + + + +Claim TRU rewards for voters +- Only can claim TRU rewards for funded loans +- Voters can claim a portion of their total rewards over time +- Claimed automatically when a user withdraws stake +chi = (TRU remaining in distributor) / (Total TRU allocated for distribution) +interest = (loan APY * term * principal) +R = Total Reward = (interest * chi) +R is distributed to voters based on their proportion of votes/total_votes +Claimable reward = R x (current time / total time) + +(account TRU staked / total TRU staked) - (amount claimed) + + +### `claimed(address id, address voter) → uint256` (external) + + + + + +### `claimable(address id, address voter) → uint256` (public) + + + + + +### `wasPredictionCorrect(address id, bool choice) → bool` (internal) + + + +Check if a prediction was correct for a specific loan and vote + + +### `status(address id) → enum TrueRatingAgency.LoanStatus` (public) + + + +Get status for a specific loan +We rely on correct implementation of LoanToken + + + +### `Allowed(address who, bool status)` + + + + + +### `LossFactorChanged(uint256 lossFactor)` + + + + + +### `BurnFactorChanged(uint256 burnFactor)` + + + + + +### `LoanSubmitted(address id)` + + + + + +### `LoanRetracted(address id)` + + + + + +### `Voted(address loanToken, address voter, bool choice, uint256 stake)` + + + + + +### `Withdrawn(address loanToken, address voter, uint256 stake, uint256 received, uint256 burned)` + + + + + +### `RewardMultiplierChanged(uint256 newRewardMultiplier)` + + + + + +### `Claimed(address loanToken, address voter, uint256 claimedReward)` + + + + + +### `SubmissionPauseStatusChanged(bool status)` + + + + + diff --git a/docs/truefi/TrueRatingAgencyV2.md b/docs/truefi/TrueRatingAgencyV2.md new file mode 100644 index 000000000..65aed5dfa --- /dev/null +++ b/docs/truefi/TrueRatingAgencyV2.md @@ -0,0 +1,308 @@ +## `TrueRatingAgencyV2` + + + +Credit prediction market for LoanTokens +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 approved +Voting Lifecycle: +- Borrowers can apply for loans at any time by deploying a LoanToken +- LoanTokens are registered with the prediction market contract +- Once registered, stkTRU holders can rate at any time +States: +Void: Rated loan is invalid +Pending: Waiting to be funded +Retracted: Rating has been cancelled +Running: Rated loan has been funded +Settled: Rated loan has been paid back in full +Defaulted: Rated loan has not been paid back in full +Liquidated: Rated loan has defaulted and stakers have been liquidated + +### `onlyAllowedSubmitters()` + + + +Only whitelisted borrowers can submit for credit ratings + +### `onlyCreator(address id)` + + + +Only loan submitter can perform certain actions + +### `onlyNotExistingLoans(address id)` + + + +Cannot submit the same loan multiple times + +### `onlyPendingLoans(address id)` + + + +Only loans in Pending state + +### `onlyFundedLoans(address id)` + + + +Only loans that have been funded + +### `calculateTotalReward(address id)` + + + +Update total TRU reward for a Loan +Reward is divided proportionally based on # TRU staked +chi = (TRU remaining in distributor) / (Total TRU allocated for distribution) +interest = (loan APY * term * principal) +R = Total Reward = (interest * chi * rewardFactor) + + + +### `initialize(contract IBurnableERC20 _TRU, contract IVoteTokenWithERC20 _stkTRU, contract IArbitraryDistributor _distributor, contract ILoanFactory _factory)` (public) + + + +Initialize Rating Agency +Distributor contract decides how much TRU is rewarded to stakers + + +### `setRatersRewardFactor(uint256 newRatersRewardFactor)` (external) + + + +Set rater reward factor. +Reward factor decides what percentage of rewarded TRU is goes to raters + +### `setRewardMultiplier(uint256 newRewardMultiplier)` (external) + + + +Set reward multiplier. +Reward multiplier increases reward for TRU stakers + +### `getNoRate(address id, address rater) → uint256` (public) + + + +Get number of NO ratings for a specific account and loan + + +### `getYesRate(address id, address rater) → uint256` (public) + + + +Get number of YES ratings for a specific account and loan + + +### `getTotalNoRatings(address id) → uint256` (public) + + + +Get total NO ratings for a specific loan + + +### `getTotalYesRatings(address id) → uint256` (public) + + + +Get total YES ratings for a specific loan + + +### `getVotingStart(address id) → uint256` (public) + + + +Get timestamp at which voting started for a specific loan + + +### `getResults(address id) → uint256, uint256, uint256` (external) + + + +Get current results for a specific loan + + +### `allowChangingAllowances(address who, bool status)` (external) + + + +Allows addresses to whitelist borrowers + +### `allow(address who, bool status)` (external) + + + +Whitelist borrowers to submit loans for rating + + +### `pauseSubmissions(bool status)` (public) + + + +Pause submitting loans for rating + + +### `submit(address id)` (external) + + + +Submit a loan for rating +Cannot submit the same loan twice + + +### `retract(address id)` (external) + + + +Remove Loan from rating agency +Can only be retracted by loan creator + + +### `rate(address id, bool choice)` (internal) + + + +Rate on a loan by staking TRU + + +### `_resetCastRatings(address id, bool choice)` (internal) + + + +Internal function to help reset ratings + + +### `resetCastRatings(address id)` (public) + + + +Cancel ratings of msg.sender + + +### `yes(address id)` (external) + + + +Rate YES on a loan by staking TRU + + +### `no(address id)` (external) + + + +Rate NO on a loan by staking TRU + + +### `toTRU(uint256 input) → uint256 output` (internal) + + + +Internal view to convert values to 8 decimals precision + + +### `claim(address id, address rater)` (external) + + + +Claim TRU rewards for raters +- Only can claim TRU rewards for funded loans +- Claimed automatically when a user withdraws stake +chi = (TRU remaining in distributor) / (Total TRU allocated for distribution) +interest = (loan APY * term * principal) +R = Total Reward = (interest * chi) +R is distributed to raters based on their proportion of ratings/total_ratings +Claimable reward = R x (current time / total time) + +(account TRU staked / total TRU staked) - (amount claimed) + + +### `claimed(address id, address rater) → uint256` (external) + + + +Get amount claimed for loan ID and rater address + + +### `claimable(address id, address rater) → uint256` (public) + + + +Get amount claimable for loan ID and rater address + + +### `status(address id) → enum TrueRatingAgencyV2.LoanStatus` (public) + + + +Get status for a specific loan +We rely on correct implementation of LoanToken + + + +### `CanChangeAllowanceChanged(address who, bool status)` + + + + + +### `Allowed(address who, bool status)` + + + + + +### `RatersRewardFactorChanged(uint256 ratersRewardFactor)` + + + + + +### `LoanSubmitted(address id)` + + + + + +### `LoanRetracted(address id)` + + + + + +### `Rated(address loanToken, address rater, bool choice, uint256 stake)` + + + + + +### `Withdrawn(address loanToken, address rater, uint256 stake, uint256 received, uint256 burned)` + + + + + +### `RewardMultiplierChanged(uint256 newRewardMultiplier)` + + + + + +### `Claimed(address loanToken, address rater, uint256 claimedReward)` + + + + + +### `SubmissionPauseStatusChanged(bool status)` + + + + + diff --git a/docs/truefi/common/ERC20.md b/docs/truefi/common/ERC20.md new file mode 100644 index 000000000..c46746d5d --- /dev/null +++ b/docs/truefi/common/ERC20.md @@ -0,0 +1,208 @@ +## `ERC20` + + + +Implementation of the {IERC20} interface. +This implementation is agnostic to the way tokens are created. This means +that a supply mechanism has to be added in a derived contract using {_mint}. +For a generic mechanism see {ERC20PresetMinterPauser}. +TIP: For a detailed writeup see our guide +https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How +to implement supply mechanisms]. +We have followed general OpenZeppelin guidelines: functions revert instead +of returning `false` on failure. This behavior is nonetheless conventional +and does not conflict with the expectations of ERC20 applications. +Additionally, an {Approval} event is emitted on calls to {transferFrom}. +This allows applications to reconstruct the allowance for all accounts just +by listening to said events. Other implementations of the EIP may not emit +these events, as it isn't required by the specification. +Finally, the non-standard {decreaseAllowance} and {increaseAllowance} +functions have been added to mitigate the well-known issues around setting +allowances. See {IERC20-approve}. + + +### `__ERC20_initialize(string name, string symbol)` (internal) + + + +Sets the values for {name} and {symbol}, initializes {decimals} with +a default value of 18. +To select a different value for {decimals}, use {_setupDecimals}. +All three of these values are immutable: they can only be set once during +construction. + +### `name() → string` (public) + + + +Returns the name of the token. + +### `symbol() → string` (public) + + + +Returns the symbol of the token, usually a shorter version of the +name. + +### `decimals() → uint8` (public) + + + +Returns the number of decimals used to get its user representation. +For example, if `decimals` equals `2`, a balance of `505` tokens should +be displayed to a user as `5,05` (`505 / 10 ** 2`). +Tokens usually opt for a value of 18, imitating the relationship between +Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is +called. +NOTE: This information is only used for _display_ purposes: it in +no way affects any of the arithmetic of the contract, including +{IERC20-balanceOf} and {IERC20-transfer}. + +### `totalSupply() → uint256` (public) + + + +See {IERC20-totalSupply}. + +### `balanceOf(address account) → uint256` (public) + + + +See {IERC20-balanceOf}. + +### `transfer(address recipient, uint256 amount) → bool` (public) + + + +See {IERC20-transfer}. +Requirements: +- `recipient` cannot be the zero address. +- the caller must have a balance of at least `amount`. + +### `allowance(address owner, address spender) → uint256` (public) + + + +See {IERC20-allowance}. + +### `approve(address spender, uint256 amount) → bool` (public) + + + +See {IERC20-approve}. +Requirements: +- `spender` cannot be the zero address. + +### `transferFrom(address sender, address recipient, uint256 amount) → bool` (public) + + + +See {IERC20-transferFrom}. +Emits an {Approval} event indicating the updated allowance. This is not +required by the EIP. See the note at the beginning of {ERC20}; +Requirements: +- `sender` and `recipient` cannot be the zero address. +- `sender` must have a balance of at least `amount`. +- the caller must have allowance for ``sender``'s tokens of at least +`amount`. + +### `increaseAllowance(address spender, uint256 addedValue) → bool` (public) + + + +Atomically increases the allowance granted to `spender` by the caller. +This is an alternative to {approve} that can be used as a mitigation for +problems described in {IERC20-approve}. +Emits an {Approval} event indicating the updated allowance. +Requirements: +- `spender` cannot be the zero address. + +### `decreaseAllowance(address spender, uint256 subtractedValue) → bool` (public) + + + +Atomically decreases the allowance granted to `spender` by the caller. +This is an alternative to {approve} that can be used as a mitigation for +problems described in {IERC20-approve}. +Emits an {Approval} event indicating the updated allowance. +Requirements: +- `spender` cannot be the zero address. +- `spender` must have allowance for the caller of at least +`subtractedValue`. + +### `_transfer(address sender, address recipient, uint256 amount)` (internal) + + + +Moves tokens `amount` from `sender` to `recipient`. +This is internal function is equivalent to {transfer}, and can be used to +e.g. implement automatic token fees, slashing mechanisms, etc. +Emits a {Transfer} event. +Requirements: +- `sender` cannot be the zero address. +- `recipient` cannot be the zero address. +- `sender` must have a balance of at least `amount`. + +### `_mint(address account, uint256 amount)` (internal) + + + +Creates `amount` tokens and assigns them to `account`, increasing +the total supply. +Emits a {Transfer} event with `from` set to the zero address. +Requirements +- `to` cannot be the zero address. + +### `_burn(address account, uint256 amount)` (internal) + + + +Destroys `amount` tokens from `account`, reducing the +total supply. +Emits a {Transfer} event with `to` set to the zero address. +Requirements +- `account` cannot be the zero address. +- `account` must have at least `amount` tokens. + +### `_approve(address owner, address spender, uint256 amount)` (internal) + + + +Sets `amount` as the allowance of `spender` over the `owner`s tokens. +This is internal function is equivalent to `approve`, and can be used to +e.g. set automatic allowances for certain subsystems, etc. +Emits an {Approval} event. +Requirements: +- `owner` cannot be the zero address. +- `spender` cannot be the zero address. + +### `_setupDecimals(uint8 decimals_)` (internal) + + + +Sets {decimals} to a value other than the default one of 18. +WARNING: This function should only be called from the constructor. Most +applications that interact with token contracts will not expect +{decimals} to ever change, and may work incorrectly if it does. + +### `_beforeTokenTransfer(address from, address to, uint256 amount)` (internal) + + + +Hook that is called before any transfer of tokens. This includes +minting and burning. +Calling conditions: +- when `from` and `to` are both non-zero, `amount` of ``from``'s tokens +will be to transferred to `to`. +- when `from` is zero, `amount` tokens will be minted for `to`. +- when `to` is zero, `amount` of ``from``'s tokens will be burned. +- `from` and `to` are never both zero. +To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + +### `updateNameAndSymbol(string __name, string __symbol)` (internal) + + + + + + diff --git a/docs/truefi/common/Initializable.md b/docs/truefi/common/Initializable.md new file mode 100644 index 000000000..622130da0 --- /dev/null +++ b/docs/truefi/common/Initializable.md @@ -0,0 +1,21 @@ +## `Initializable` + + + +Helper contract to support initializer functions. To use it, replace +the constructor with a function that has the `initializer` modifier. +WARNING: Unlike constructors, initializer functions must be manually +invoked. This applies both to deploying an Initializable contract, as well +as extending an Initializable contract via inheritance. +WARNING: When used with inheritance, manual care must be taken to not invoke +a parent initializer twice, or ensure that all initializers are idempotent, +because this is not dealt with automatically as with constructors. + +### `initializer()` + + + +Modifier to use in the initializer function of a contract. + + + diff --git a/docs/truefi/common/Ownable.md b/docs/truefi/common/Ownable.md new file mode 100644 index 000000000..46372a1b7 --- /dev/null +++ b/docs/truefi/common/Ownable.md @@ -0,0 +1,55 @@ +## `Ownable` + + + +Contract module which provides a basic access control mechanism, where +there is an account (an owner) that can be granted exclusive access to +specific functions. +By default, the owner account will be the one that deploys the contract. This +can later be changed with {transferOwnership}. +This module is used through inheritance. It will make available the modifier +`onlyOwner`, which can be applied to your functions to restrict their use to +the owner. + +### `onlyOwner()` + + + +Throws if called by any account other than the owner. + + +### `initialize()` (internal) + + + +Initializes the contract setting the deployer as the initial owner. + +### `owner() → address` (public) + + + +Returns the address of the current owner. + +### `renounceOwnership()` (public) + + + +Leaves the contract without owner. It will not be possible to call +`onlyOwner` functions anymore. Can only be called by the current owner. +NOTE: Renouncing ownership will leave the contract without an owner, +thereby removing any functionality that is only available to the owner. + +### `transferOwnership(address newOwner)` (public) + + + +Transfers ownership of the contract to a new account (`newOwner`). +Can only be called by the current owner. + + +### `OwnershipTransferred(address previousOwner, address newOwner)` + + + + + diff --git a/docs/truefi/distributors/ArbitraryDistributor.md b/docs/truefi/distributors/ArbitraryDistributor.md new file mode 100644 index 000000000..2658e469d --- /dev/null +++ b/docs/truefi/distributors/ArbitraryDistributor.md @@ -0,0 +1,57 @@ +## `ArbitraryDistributor` + +Distribute TRU to a smart contract + + +Allows for arbitrary claiming of TRU by a farm contract +Contracts are registered to receive distributions. Once registered, +a farm contract can claim TRU from the distributor. +- Owner can withdraw funds in case distribution need to be re-allocated + +### `onlyBeneficiary()` + + + +Only beneficiary can receive TRU + + +### `initialize(address _beneficiary, contract IERC20 _trustToken, uint256 _amount)` (public) + + + +Initialize distributor + + +### `setBeneficiaryStatus(address _beneficiary, bool _status)` (public) + + + +Set beneficiary status + + +### `distribute(uint256 _amount)` (public) + + + +Distribute arbitrary number of tokens + + +### `empty()` (public) + + + +Withdraw funds (for instance if owner decides to create a new distribution) and end distribution cycle + + +### `Distributed(uint256 amount)` + + + + + +### `BeneficiaryStatusChanged(address beneficiary, bool status)` + + + + + diff --git a/docs/truefi/distributors/LinearTrueDistributor.md b/docs/truefi/distributors/LinearTrueDistributor.md new file mode 100644 index 000000000..21010c921 --- /dev/null +++ b/docs/truefi/distributors/LinearTrueDistributor.md @@ -0,0 +1,77 @@ +## `LinearTrueDistributor` + +Distribute TRU in a linear fashion + + +Distributor contract which uses a linear distribution +Contracts are registered to receive distributions. Once registered, +a farm contract can claim TRU from the distributor. +- Distributions are based on time. +- Owner can withdraw funds in case distribution need to be re-allocated + + +### `initialize(uint256 _distributionStart, uint256 _duration, uint256 _amount, contract IERC20 _trustToken)` (public) + + + +Initialize distributor + + +### `setFarm(address newFarm)` (external) + + + +Set contract to receive distributions +Will distribute to previous contract if farm already exists + + +### `distribute()` (public) + + + +Distribute tokens to farm in linear fashion based on time + +### `nextDistribution() → uint256` (public) + + + +Calculate next distribution amount + + +### `empty()` (public) + + + +Withdraw funds (for instance if owner decides to create a new distribution) +Distributes remaining funds before withdrawing +Ends current distribution + +### `setDailyDistribution(uint256 dailyDistribution)` (public) + + + +Change amount of tokens distributed daily by changing total distributed amount + + + +### `FarmChanged(address newFarm)` + + + +Emitted when the farm address is changed + + +### `TotalAmountChanged(uint256 newTotalAmount)` + + + +Emitted when the total distributed amount is changed + + +### `Distributed(uint256 amount)` + + + +Emitted when a distribution occurs + + diff --git a/docs/truefi/distributors/RatingAgencyV2Distributor.md b/docs/truefi/distributors/RatingAgencyV2Distributor.md new file mode 100644 index 000000000..66711b9b8 --- /dev/null +++ b/docs/truefi/distributors/RatingAgencyV2Distributor.md @@ -0,0 +1,57 @@ +## `RatingAgencyV2Distributor` + +Distribute TRU to a smart contract + + +Allows for arbitrary claiming of TRU by a farm contract +Contracts are registered to receive distributions. Once registered, +a farm contract can claim TRU from the distributor. +- Owner can withdraw funds in case distribution need to be re-allocated + +### `onlyBeneficiary()` + + + +Only beneficiary can receive TRU + + +### `initialize(address _beneficiary, contract IERC20 _trustToken)` (public) + + + +Initialize distributor + + +### `setBeneficiaryStatus(address _beneficiary, bool _status)` (public) + + + +Owner can set beneficiary status + + +### `distribute(uint256 _amount)` (public) + + + +Distribute arbitrary number of tokens + + +### `empty()` (public) + + + +Withdraw funds (for instance if owner decides to create a new distribution) and end distribution cycle + + +### `Distributed(uint256 amount)` + + + + + +### `BeneficiaryStatusChanged(address beneficiary, bool status)` + + + + + diff --git a/docs/truefi/interface/IArbitraryDistributor.md b/docs/truefi/interface/IArbitraryDistributor.md new file mode 100644 index 000000000..858899a82 --- /dev/null +++ b/docs/truefi/interface/IArbitraryDistributor.md @@ -0,0 +1,38 @@ +## `IArbitraryDistributor` + + + + + + +### `amount() → uint256` (external) + + + + + +### `remaining() → uint256` (external) + + + + + +### `beneficiary() → address` (external) + + + + + +### `distribute(uint256 _amount)` (external) + + + + + +### `empty()` (external) + + + + + + diff --git a/docs/truefi/interface/ICurve.md b/docs/truefi/interface/ICurve.md new file mode 100644 index 000000000..061b3a703 --- /dev/null +++ b/docs/truefi/interface/ICurve.md @@ -0,0 +1,20 @@ +## `ICurve` + + + + + + +### `calc_token_amount(uint256[4] amounts, bool deposit) → uint256` (external) + + + + + +### `get_virtual_price() → uint256` (external) + + + + + + diff --git a/docs/truefi/interface/ICurveGauge.md b/docs/truefi/interface/ICurveGauge.md new file mode 100644 index 000000000..90c60222a --- /dev/null +++ b/docs/truefi/interface/ICurveGauge.md @@ -0,0 +1,32 @@ +## `ICurveGauge` + + + + + + +### `balanceOf(address depositor) → uint256` (external) + + + + + +### `minter() → contract ICurveMinter` (external) + + + + + +### `deposit(uint256 amount)` (external) + + + + + +### `withdraw(uint256 amount)` (external) + + + + + + diff --git a/docs/truefi/interface/ICurveMinter.md b/docs/truefi/interface/ICurveMinter.md new file mode 100644 index 000000000..d469b01dd --- /dev/null +++ b/docs/truefi/interface/ICurveMinter.md @@ -0,0 +1,20 @@ +## `ICurveMinter` + + + + + + +### `mint(address gauge)` (external) + + + + + +### `token() → contract IERC20` (external) + + + + + + diff --git a/docs/truefi/interface/ICurvePool.md b/docs/truefi/interface/ICurvePool.md new file mode 100644 index 000000000..f849005ef --- /dev/null +++ b/docs/truefi/interface/ICurvePool.md @@ -0,0 +1,44 @@ +## `ICurvePool` + + + + + + +### `add_liquidity(uint256[4] amounts, uint256 min_mint_amount)` (external) + + + + + +### `remove_liquidity_one_coin(uint256 _token_amount, int128 i, uint256 min_amount, bool donate_dust)` (external) + + + + + +### `calc_withdraw_one_coin(uint256 _token_amount, int128 i) → uint256` (external) + + + + + +### `token() → contract IERC20` (external) + + + + + +### `curve() → contract ICurve` (external) + + + + + +### `coins(int128 id) → contract IYToken` (external) + + + + + + diff --git a/docs/truefi/interface/ILoanFactory.md b/docs/truefi/interface/ILoanFactory.md new file mode 100644 index 000000000..3d6bd2435 --- /dev/null +++ b/docs/truefi/interface/ILoanFactory.md @@ -0,0 +1,20 @@ +## `ILoanFactory` + + + + + + +### `createLoanToken(uint256 _amount, uint256 _term, uint256 _apy)` (external) + + + + + +### `isLoanToken(address) → bool` (external) + + + + + + diff --git a/docs/truefi/interface/ILoanToken.md b/docs/truefi/interface/ILoanToken.md new file mode 100644 index 000000000..f48000c92 --- /dev/null +++ b/docs/truefi/interface/ILoanToken.md @@ -0,0 +1,164 @@ +## `ILoanToken` + + + + + + +### `borrower() → address` (external) + + + + + +### `amount() → uint256` (external) + + + + + +### `term() → uint256` (external) + + + + + +### `apy() → uint256` (external) + + + + + +### `start() → uint256` (external) + + + + + +### `lender() → address` (external) + + + + + +### `debt() → uint256` (external) + + + + + +### `profit() → uint256` (external) + + + + + +### `status() → enum ILoanToken.Status` (external) + + + + + +### `borrowerFee() → uint256` (external) + + + + + +### `receivedAmount() → uint256` (external) + + + + + +### `isLoanToken() → bool` (external) + + + + + +### `getParameters() → uint256, uint256, uint256` (external) + + + + + +### `fund()` (external) + + + + + +### `withdraw(address _beneficiary)` (external) + + + + + +### `close()` (external) + + + + + +### `liquidate()` (external) + + + + + +### `redeem(uint256 _amount)` (external) + + + + + +### `repay(address _sender, uint256 _amount)` (external) + + + + + +### `reclaim()` (external) + + + + + +### `allowTransfer(address account, bool _status)` (external) + + + + + +### `repaid() → uint256` (external) + + + + + +### `balance() → uint256` (external) + + + + + +### `value(uint256 _balance) → uint256` (external) + + + + + +### `currencyToken() → contract IERC20` (external) + + + + + +### `version() → uint8` (external) + + + + + + diff --git a/docs/truefi/interface/IMockTruPriceOracle.md b/docs/truefi/interface/IMockTruPriceOracle.md new file mode 100644 index 000000000..884a0f627 --- /dev/null +++ b/docs/truefi/interface/IMockTruPriceOracle.md @@ -0,0 +1,14 @@ +## `IMockTruPriceOracle` + + + + + + +### `toTru(uint256 amount) → uint256` (external) + + + + + + diff --git a/docs/truefi/interface/IStakingPool.md b/docs/truefi/interface/IStakingPool.md new file mode 100644 index 000000000..b6cafdafb --- /dev/null +++ b/docs/truefi/interface/IStakingPool.md @@ -0,0 +1,26 @@ +## `IStakingPool` + + + + + + +### `stakeSupply() → uint256` (external) + + + + + +### `withdraw(uint256 amount)` (external) + + + + + +### `payFee(uint256 amount, uint256 endTime)` (external) + + + + + + diff --git a/docs/truefi/interface/ITruPriceOracle.md b/docs/truefi/interface/ITruPriceOracle.md new file mode 100644 index 000000000..f301c3ee8 --- /dev/null +++ b/docs/truefi/interface/ITruPriceOracle.md @@ -0,0 +1,20 @@ +## `ITruPriceOracle` + + + + + + +### `usdToTru(uint256 amount) → uint256` (external) + + + + + +### `truToUsd(uint256 amount) → uint256` (external) + + + + + + diff --git a/docs/truefi/interface/ITrueDistributor.md b/docs/truefi/interface/ITrueDistributor.md new file mode 100644 index 000000000..138405d5c --- /dev/null +++ b/docs/truefi/interface/ITrueDistributor.md @@ -0,0 +1,38 @@ +## `ITrueDistributor` + + + + + + +### `trustToken() → contract IERC20` (external) + + + + + +### `farm() → address` (external) + + + + + +### `distribute()` (external) + + + + + +### `nextDistribution() → uint256` (external) + + + + + +### `empty()` (external) + + + + + + diff --git a/docs/truefi/interface/ITrueFarm.md b/docs/truefi/interface/ITrueFarm.md new file mode 100644 index 000000000..6201244b0 --- /dev/null +++ b/docs/truefi/interface/ITrueFarm.md @@ -0,0 +1,62 @@ +## `ITrueFarm` + + + + + + +### `stakingToken() → contract IERC20` (external) + + + + + +### `trustToken() → contract IERC20` (external) + + + + + +### `trueDistributor() → contract ITrueDistributor` (external) + + + + + +### `name() → string` (external) + + + + + +### `totalStaked() → uint256` (external) + + + + + +### `stake(uint256 amount)` (external) + + + + + +### `unstake(uint256 amount)` (external) + + + + + +### `claim()` (external) + + + + + +### `exit(uint256 amount)` (external) + + + + + + diff --git a/docs/truefi/interface/ITrueFiPool.md b/docs/truefi/interface/ITrueFiPool.md new file mode 100644 index 000000000..761c2d005 --- /dev/null +++ b/docs/truefi/interface/ITrueFiPool.md @@ -0,0 +1,56 @@ +## `ITrueFiPool` + +TruePool is an ERC20 which represents a share of a pool +This contract can be used to wrap opportunities to be compatible +with TrueFi and allow users to directly opt-in through the TUSD contract +Each TruePool is also a staking opportunity for TRU + + + + +### `currencyToken() → contract IERC20` (external) + + + +pool token (TUSD) + +### `stakeToken() → contract IERC20` (external) + + + +stake token (TRU) + +### `join(uint256 amount)` (external) + + + +join pool +1. Transfer TUSD from sender +2. Mint pool tokens based on value to sender + +### `exit(uint256 amount)` (external) + + + +exit pool +1. Transfer pool tokens from sender +2. Burn pool tokens +3. Transfer value of pool tokens in TUSD to sender + +### `borrow(uint256 amount, uint256 fee)` (external) + + + +borrow from pool +1. Transfer TUSD to sender +2. Only lending pool should be allowed to call this + +### `repay(uint256 amount)` (external) + + + +join pool +1. Transfer TUSD from sender +2. Only lending pool should be allowed to call this + + diff --git a/docs/truefi/interface/ITrueLender.md b/docs/truefi/interface/ITrueLender.md new file mode 100644 index 000000000..1405cba09 --- /dev/null +++ b/docs/truefi/interface/ITrueLender.md @@ -0,0 +1,20 @@ +## `ITrueLender` + + + + + + +### `value() → uint256` (external) + + + + + +### `distribute(address recipient, uint256 numerator, uint256 denominator)` (external) + + + + + + diff --git a/docs/truefi/interface/ITrueRatingAgency.md b/docs/truefi/interface/ITrueRatingAgency.md new file mode 100644 index 000000000..3bae36705 --- /dev/null +++ b/docs/truefi/interface/ITrueRatingAgency.md @@ -0,0 +1,50 @@ +## `ITrueRatingAgency` + + + + + + +### `getResults(address id) → uint256, uint256, uint256` (external) + + + + + +### `submit(address id)` (external) + + + + + +### `retract(address id)` (external) + + + + + +### `yes(address id, uint256 stake)` (external) + + + + + +### `no(address id, uint256 stake)` (external) + + + + + +### `withdraw(address id, uint256 stake)` (external) + + + + + +### `claim(address id, address voter)` (external) + + + + + + diff --git a/docs/truefi/interface/ITrueRatingAgencyV2.md b/docs/truefi/interface/ITrueRatingAgencyV2.md new file mode 100644 index 000000000..2b381f31a --- /dev/null +++ b/docs/truefi/interface/ITrueRatingAgencyV2.md @@ -0,0 +1,44 @@ +## `ITrueRatingAgencyV2` + + + + + + +### `getResults(address id) → uint256, uint256, uint256` (external) + + + + + +### `submit(address id)` (external) + + + + + +### `retract(address id)` (external) + + + + + +### `yes(address id)` (external) + + + + + +### `no(address id)` (external) + + + + + +### `claim(address id, address voter)` (external) + + + + + + diff --git a/docs/truefi/interface/IUniswapPair.md b/docs/truefi/interface/IUniswapPair.md new file mode 100644 index 000000000..60f502557 --- /dev/null +++ b/docs/truefi/interface/IUniswapPair.md @@ -0,0 +1,14 @@ +## `IUniswapPair` + + + + + + +### `getReserves() → uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast` (external) + + + + + + diff --git a/docs/truefi/interface/IUniswapRouter.md b/docs/truefi/interface/IUniswapRouter.md new file mode 100644 index 000000000..3a541faac --- /dev/null +++ b/docs/truefi/interface/IUniswapRouter.md @@ -0,0 +1,14 @@ +## `IUniswapRouter` + + + + + + +### `swapExactTokensForTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline) → uint256[] amounts` (external) + + + + + + diff --git a/docs/truefi/interface/IYToken.md b/docs/truefi/interface/IYToken.md new file mode 100644 index 000000000..5f81a60a0 --- /dev/null +++ b/docs/truefi/interface/IYToken.md @@ -0,0 +1,14 @@ +## `IYToken` + + + + + + +### `getPricePerFullShare() → uint256` (external) + + + + + + diff --git a/docs/truefi/mocks/MockCurve.md b/docs/truefi/mocks/MockCurve.md new file mode 100644 index 000000000..637b49e5c --- /dev/null +++ b/docs/truefi/mocks/MockCurve.md @@ -0,0 +1,32 @@ +## `MockCurve` + + + + + + +### `calc_token_amount(uint256[4] amounts, bool) → uint256` (external) + + + + + +### `set_withdraw_price(uint256 price)` (external) + + + + + +### `get_virtual_price() → uint256` (external) + + + + + +### `burn300kGas()` (public) + + + + + + diff --git a/docs/truefi/mocks/MockCurvePool.md b/docs/truefi/mocks/MockCurvePool.md new file mode 100644 index 000000000..acc24bc2e --- /dev/null +++ b/docs/truefi/mocks/MockCurvePool.md @@ -0,0 +1,56 @@ +## `MockCurvePool` + + + + + + +### `initialize(contract IERC20 _token)` (public) + + + + + +### `add_liquidity(uint256[4] amounts, uint256)` (external) + + + + + +### `remove_liquidity_one_coin(uint256 _token_amount, int128, uint256, bool)` (external) + + + + + +### `calc_withdraw_one_coin(uint256, int128) → uint256` (external) + + + + + +### `set_withdraw_price(uint256 price)` (external) + + + + + +### `token() → contract IERC20` (external) + + + + + +### `curve() → contract ICurve` (external) + + + + + +### `coins(int128) → contract IYToken` (external) + + + + + + diff --git a/docs/truefi/mocks/MockLoanFactory.md b/docs/truefi/mocks/MockLoanFactory.md new file mode 100644 index 000000000..d73f753da --- /dev/null +++ b/docs/truefi/mocks/MockLoanFactory.md @@ -0,0 +1,14 @@ +## `MockLoanFactory` + + + + + + +### `setLender(address newLender)` (external) + + + + + + diff --git a/docs/truefi/mocks/MockLog.md b/docs/truefi/mocks/MockLog.md new file mode 100644 index 000000000..571b12dab --- /dev/null +++ b/docs/truefi/mocks/MockLog.md @@ -0,0 +1,14 @@ +## `MockLog` + + + + + + +### `ln(uint256 x) → int128` (public) + + + + + + diff --git a/docs/truefi/mocks/MockStakingPool.md b/docs/truefi/mocks/MockStakingPool.md new file mode 100644 index 000000000..561648f9e --- /dev/null +++ b/docs/truefi/mocks/MockStakingPool.md @@ -0,0 +1,26 @@ +## `MockStakingPool` + + + + + + +### `constructor(contract ITrueFiPool _pool)` (public) + + + + + +### `unstake()` (public) + + + + + +### `payFee(uint256 amount, uint256)` (external) + + + + + + diff --git a/docs/truefi/mocks/MockTruPriceOracle.md b/docs/truefi/mocks/MockTruPriceOracle.md new file mode 100644 index 000000000..241b80944 --- /dev/null +++ b/docs/truefi/mocks/MockTruPriceOracle.md @@ -0,0 +1,20 @@ +## `MockTruPriceOracle` + + + + + + +### `usdToTru(uint256 amount) → uint256` (external) + + + + + +### `truToUsd(uint256 amount) → uint256` (external) + + + + + + diff --git a/docs/truefi/mocks/MockTrueLender.md b/docs/truefi/mocks/MockTrueLender.md new file mode 100644 index 000000000..ac04fea65 --- /dev/null +++ b/docs/truefi/mocks/MockTrueLender.md @@ -0,0 +1,14 @@ +## `MockTrueLender` + + + + + + +### `setPool(contract ITrueFiPool newPool)` (external) + + + + + + diff --git a/docs/truefi/mocks/MockYToken.md b/docs/truefi/mocks/MockYToken.md new file mode 100644 index 000000000..d702284b3 --- /dev/null +++ b/docs/truefi/mocks/MockYToken.md @@ -0,0 +1,14 @@ +## `MockYToken` + + + + + + +### `getPricePerFullShare() → uint256` (external) + + + + + + diff --git a/docs/truefi/mocks/PoolArbitrageTest.md b/docs/truefi/mocks/PoolArbitrageTest.md new file mode 100644 index 000000000..14a4386b3 --- /dev/null +++ b/docs/truefi/mocks/PoolArbitrageTest.md @@ -0,0 +1,14 @@ +## `PoolArbitrageTest` + + + + + + +### `joinExit(contract ITrueFiPool pool)` (external) + + + + + + diff --git a/docs/trusttoken/TimeLockRegistry.md b/docs/trusttoken/TimeLockRegistry.md new file mode 100644 index 000000000..b7646fcf5 --- /dev/null +++ b/docs/trusttoken/TimeLockRegistry.md @@ -0,0 +1,58 @@ +## `TimeLockRegistry` + +Register Lockups for TimeLocked ERC20 Token + + +This contract allows owner to register distributions for a TimeLockedToken +To register a distribution, register method should be called by the owner. +claim() should then be called by account registered to recieve tokens under lockup period +If case of a mistake, owner can cancel registration +Note this contract must be setup in TimeLockedToken's setTimeLockRegistry() function + + +### `initialize(contract TimeLockedToken _token)` (external) + + + +Initalize function so this contract can be behind a proxy + + +### `register(address receiver, uint256 distribution)` (external) + + + +Register new SAFT account + + +### `cancel(address receiver)` (external) + + + +Cancel distribution registration + + +### `claim()` (external) + + + +Claim tokens due amount + + +### `Register(address receiver, uint256 distribution)` + + + + + +### `Cancel(address receiver, uint256 distribution)` + + + + + +### `Claim(address account, uint256 distribution)` + + + + + diff --git a/docs/trusttoken/TimeLockedToken.md b/docs/trusttoken/TimeLockedToken.md new file mode 100644 index 000000000..0881a5be3 --- /dev/null +++ b/docs/trusttoken/TimeLockedToken.md @@ -0,0 +1,131 @@ +## `TimeLockedToken` + +Time Locked ERC20 Token + + +Contract which gives the ability to time-lock tokens +The registerLockup() function allows an account to transfer +its tokens to another account, locking them according to the +distribution epoch periods +By overriding the balanceOf(), transfer(), and transferFrom() +functions in ERC20, an account can show its full, post-distribution +balance but only transfer or spend up to an allowed amount +Every time an epoch passes, a portion of previously non-spendable tokens +are allowed to be transferred, and after all epochs have passed, the full +account balance is unlocked + +### `onlyTimeLockRegistry()` + + + + + + +### `setTimeLockRegistry(address newTimeLockRegistry)` (external) + + + +Set TimeLockRegistry address + + +### `lockReturns()` (external) + + + +Permanently lock transfers to return address +Lock returns so there isn't always a way to send locked tokens + +### `_transfer(address _from, address _to, uint256 _value)` (internal) + + + +Transfer function which includes unlocked tokens +Locked tokens can always be transfered back to the returns address +Transferring to owner allows re-issuance of funds through registry + + +### `transferToOwner(address _from, uint256 _value)` (internal) + + + +Transfer tokens to owner. Used only when returns allowed. + + +### `_burn(address _from, uint256 _value)` (internal) + + + +Check if amount we want to burn is unlocked before burning + + +### `registerLockup(address receiver, uint256 amount)` (external) + + + +Transfer tokens to another account under the lockup schedule +Emits a transfer event showing a transfer to the recipient +Only the registry can call this function + + +### `lockedBalance(address account) → uint256` (public) + + + +Get locked balance for an account + + +### `unlockedBalance(address account) → uint256` (public) + + + +Get unlocked balance for an account + + +### `_balanceOf(address account) → uint256` (internal) + + + + + +### `epochsPassed() → uint256` (public) + + + + + +### `epochsLeft() → uint256` (public) + + + + + +### `nextEpoch() → uint256` (public) + + + +Get timestamp of next epoch +Will revert if all epochs have passed + + +### `latestEpoch() → uint256` (public) + + + +Get timestamp of latest epoch + + +### `finalEpoch() → uint256` (public) + + + +Get timestamp of final epoch + + +### `lockStart() → uint256` (public) + + + +Get timestamp of locking period start + + + diff --git a/docs/trusttoken/TrustToken.md b/docs/trusttoken/TrustToken.md new file mode 100644 index 000000000..ae84e3036 --- /dev/null +++ b/docs/trusttoken/TrustToken.md @@ -0,0 +1,55 @@ +## `TrustToken` + + + +The TrustToken contract is a claimable contract where the +owner can only mint or transfer ownership. TrustTokens use 8 decimals +in order to prevent rewards from getting stuck in the remainder on division. +Tolerates dilution to slash stake and accept rewards. + + +### `initialize()` (public) + + + +initialize trusttoken and give ownership to sender +This is necessary to set ownership for proxy + +### `mint(address _to, uint256 _amount)` (external) + + + +mint TRU +Can never mint more than MAX_SUPPLY = 1.45 billion + +### `burn(uint256 amount)` (external) + + + + + +### `decimals() → uint8` (public) + + + + + +### `rounding() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + + diff --git a/docs/trusttoken/common/ClaimableContract.md b/docs/trusttoken/common/ClaimableContract.md new file mode 100644 index 000000000..7ee93b3aa --- /dev/null +++ b/docs/trusttoken/common/ClaimableContract.md @@ -0,0 +1,60 @@ +## `ClaimableContract` + + + +The ClaimableContract contract is a copy of Claimable Contract by Zeppelin. +and provides basic authorization control functions. Inherits storage layout of +ProxyStorage. + +### `onlyOwner()` + + + +Throws if called by any account other than the owner. + +### `onlyPendingOwner()` + + + +Modifier throws if called by any account other than the pendingOwner. + + +### `owner() → address` (public) + + + + + +### `pendingOwner() → address` (public) + + + + + +### `constructor()` (public) + + + +sets the original `owner` of the contract to the sender +at construction. Must then be reinitialized + +### `transferOwnership(address newOwner)` (public) + + + +Allows the current owner to set the pendingOwner address. + + +### `claimOwnership()` (public) + + + +Allows the pendingOwner address to finalize the transfer. + + +### `OwnershipTransferred(address previousOwner, address newOwner)` + + + + + diff --git a/docs/trusttoken/common/ERC20.md b/docs/trusttoken/common/ERC20.md new file mode 100644 index 000000000..be61c72c9 --- /dev/null +++ b/docs/trusttoken/common/ERC20.md @@ -0,0 +1,180 @@ +## `ERC20` + + + +Implementation of the {IERC20} interface. +This implementation is agnostic to the way tokens are created. This means +that a supply mechanism has to be added in a derived contract using {_mint}. +For a generic mechanism see {ERC20PresetMinterPauser}. +TIP: For a detailed writeup see our guide +https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How +to implement supply mechanisms]. +We have followed general OpenZeppelin guidelines: functions revert instead +of returning `false` on failure. This behavior is nonetheless conventional +and does not conflict with the expectations of ERC20 applications. +Additionally, an {Approval} event is emitted on calls to {transferFrom}. +This allows applications to reconstruct the allowance for all accounts just +by listening to said events. Other implementations of the EIP may not emit +these events, as it isn't required by the specification. +Finally, the non-standard {decreaseAllowance} and {increaseAllowance} +functions have been added to mitigate the well-known issues around setting +allowances. See {IERC20-approve}. + + +### `name() → string` (public) + + + +Returns the name of the token. + +### `symbol() → string` (public) + + + +Returns the symbol of the token, usually a shorter version of the +name. + +### `decimals() → uint8` (public) + + + +Returns the number of decimals used to get its user representation. +For example, if `decimals` equals `2`, a balance of `505` tokens should +be displayed to a user as `5,05` (`505 / 10 ** 2`). +Tokens usually opt for a value of 18, imitating the relationship between +Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is +called. +NOTE: This information is only used for _display_ purposes: it in +no way affects any of the arithmetic of the contract, including +{IERC20-balanceOf} and {IERC20-transfer}. + +### `transfer(address recipient, uint256 amount) → bool` (public) + + + +See {IERC20-transfer}. +Requirements: +- `recipient` cannot be the zero address. +- the caller must have a balance of at least `amount`. + +### `approve(address spender, uint256 amount) → bool` (public) + + + +See {IERC20-approve}. +Requirements: +- `spender` cannot be the zero address. + +### `transferFrom(address sender, address recipient, uint256 amount) → bool` (public) + + + +See {IERC20-transferFrom}. +Emits an {Approval} event indicating the updated allowance. This is not +required by the EIP. See the note at the beginning of {ERC20}; +Requirements: +- `sender` and `recipient` cannot be the zero address. +- `sender` must have a balance of at least `amount`. +- the caller must have allowance for ``sender``'s tokens of at least +`amount`. + +### `increaseAllowance(address spender, uint256 addedValue) → bool` (public) + + + +Atomically increases the allowance granted to `spender` by the caller. +This is an alternative to {approve} that can be used as a mitigation for +problems described in {IERC20-approve}. +Emits an {Approval} event indicating the updated allowance. +Requirements: +- `spender` cannot be the zero address. + +### `decreaseAllowance(address spender, uint256 subtractedValue) → bool` (public) + + + +Atomically decreases the allowance granted to `spender` by the caller. +This is an alternative to {approve} that can be used as a mitigation for +problems described in {IERC20-approve}. +Emits an {Approval} event indicating the updated allowance. +Requirements: +- `spender` cannot be the zero address. +- `spender` must have allowance for the caller of at least +`subtractedValue`. + +### `_transfer(address sender, address recipient, uint256 amount)` (internal) + + + +Moves tokens `amount` from `sender` to `recipient`. +This is internal function is equivalent to {transfer}, and can be used to +e.g. implement automatic token fees, slashing mechanisms, etc. +Emits a {Transfer} event. +Requirements: +- `sender` cannot be the zero address. +- `recipient` cannot be the zero address. +- `sender` must have a balance of at least `amount`. + +### `_mint(address account, uint256 amount)` (internal) + + + +Creates `amount` tokens and assigns them to `account`, increasing +the total supply. +Emits a {Transfer} event with `from` set to the zero address. +Requirements +- `to` cannot be the zero address. + +### `_burn(address account, uint256 amount)` (internal) + + + +Destroys `amount` tokens from `account`, reducing the +total supply. +Emits a {Transfer} event with `to` set to the zero address. +Requirements +- `account` cannot be the zero address. +- `account` must have at least `amount` tokens. + +### `_approve(address owner, address spender, uint256 amount)` (internal) + + + +Sets `amount` as the allowance of `spender` over the `owner`s tokens. +This is internal function is equivalent to `approve`, and can be used to +e.g. set automatic allowances for certain subsystems, etc. +Emits an {Approval} event. +Requirements: +- `owner` cannot be the zero address. +- `spender` cannot be the zero address. + +### `_beforeTokenTransfer(address from, address to, uint256 amount)` (internal) + + + +Hook that is called before any transfer of tokens. This includes +minting and burning. +Calling conditions: +- when `from` and `to` are both non-zero, `amount` of ``from``'s tokens +will be to transferred to `to`. +- when `from` is zero, `amount` tokens will be minted for `to`. +- when `to` is zero, `amount` of ``from``'s tokens will be burned. +- `from` and `to` are never both zero. +To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + + +### `Transfer(address from, address to, uint256 value)` + + + +Emitted when `value` tokens are moved from one account (`from`) to +another (`to`). +Note that `value` may be zero. + +### `Approval(address owner, address spender, uint256 value)` + + + +Emitted when the allowance of a `spender` for an `owner` is set by +a call to {approve}. `value` is the new allowance. + diff --git a/docs/trusttoken/common/ProxyStorage.md b/docs/trusttoken/common/ProxyStorage.md new file mode 100644 index 000000000..1d1960e70 --- /dev/null +++ b/docs/trusttoken/common/ProxyStorage.md @@ -0,0 +1,10 @@ +## `ProxyStorage` + +All storage must be declared here +New storage must be appended to the end +Never remove items from this list + + + + + diff --git a/docs/trusttoken/interface/IBurnableERC20.md b/docs/trusttoken/interface/IBurnableERC20.md new file mode 100644 index 000000000..750a4fd5c --- /dev/null +++ b/docs/trusttoken/interface/IBurnableERC20.md @@ -0,0 +1,14 @@ +## `IBurnableERC20` + + + + + + +### `burn(uint256 amount)` (external) + + + + + + diff --git a/docs/trusttoken/mocks/MockERC20Token.md b/docs/trusttoken/mocks/MockERC20Token.md new file mode 100644 index 000000000..aa2fae3ac --- /dev/null +++ b/docs/trusttoken/mocks/MockERC20Token.md @@ -0,0 +1,56 @@ +## `MockERC20Token` + + + + + + +### `registry() → contract Registry` (public) + + + + + +### `setRegistry(contract Registry _registry)` (external) + + + + + +### `mint(address _to, uint256 _value)` (external) + + + + + +### `burn(uint256 _value)` (external) + + + + + +### `rounding() → uint8` (public) + + + + + +### `decimals() → uint8` (public) + + + + + +### `name() → string` (public) + + + + + +### `symbol() → string` (public) + + + + + + diff --git a/flatten/ArbitraryDistributor.sol b/flatten/ArbitraryDistributor.sol index 880fd55ce..30639ed20 100644 --- a/flatten/ArbitraryDistributor.sol +++ b/flatten/ArbitraryDistributor.sol @@ -519,7 +519,12 @@ contract ArbitraryDistributor is IArbitraryDistributor, Ownable { _; } - function setBeneficiaryStatus(address _beneficiary, bool _status) public { + /** + * @dev Set beneficiary status + * @param _beneficiary Contract which can claim TRU + * @param _status Boolean to set whether beneficiary can claim TRU + */ + function setBeneficiaryStatus(address _beneficiary, bool _status) public onlyOwner { beneficiaries[_beneficiary] = _status; emit BeneficiaryStatusChanged(_beneficiary, _status); } diff --git a/flatten/GovernorAlpha.sol b/flatten/GovernorAlpha.sol index 18ac5b49a..81ff31812 100644 --- a/flatten/GovernorAlpha.sol +++ b/flatten/GovernorAlpha.sol @@ -243,7 +243,7 @@ interface IVoteTokenWithERC20 is IVoteToken, IERC20 {} // Root file: contracts/governance/GovernorAlpha.sol -// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol +// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/c5fcc34222693ad5f547b14ed01ce719b5f4b000/contracts/Governance/GovernorAlpha.sol // Copyright 2020 Compound Labs, Inc. // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -263,15 +263,12 @@ pragma experimental ABIEncoderV2; 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 @@ -281,14 +278,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 @@ -524,7 +519,7 @@ contract GovernorAlpha is ClaimableContract { /** * @dev Get the actions of a selected proposal * @param proposalId ID of a proposal - * return An array of target addresses, an array of proposal values, an array of proposal singatures, and an array of calldata + * return An array of target addresses, an array of proposal values, an array of proposal signatures, and an array of calldata */ function getActions(uint proposalId) public view returns (address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas) { Proposal storage p = proposals[proposalId]; @@ -688,7 +683,7 @@ contract GovernorAlpha is ClaimableContract { * @param blockNumber The block number at which the getPriorVotes() check * @return The sum of PriorVotes from TRU and stkTRU */ - function countVotes(address account, uint blockNumber) internal view returns (uint96) { + function countVotes(address account, uint blockNumber) public view returns (uint96) { uint96 truVote = trustToken.getPriorVotes(account, blockNumber); uint96 stkTRUVote = stkTRU.getPriorVotes(account, blockNumber); uint96 totalVote = add96(truVote, stkTRUVote, "GovernorAlpha: countVotes addition overflow"); diff --git a/flatten/ITruPriceOracle.sol b/flatten/ITruPriceOracle.sol index 9ccf3a15d..cf884c30d 100644 --- a/flatten/ITruPriceOracle.sol +++ b/flatten/ITruPriceOracle.sol @@ -24,11 +24,13 @@ */ // https://github.com/trusttoken/smart-contracts -// Root file: contracts/governance/interface/ITruPriceOracle.sol +// Root file: contracts/truefi/interface/ITruPriceOracle.sol // SPDX-License-Identifier: MIT pragma solidity 0.6.10; interface ITruPriceOracle { function usdToTru(uint256 amount) external view returns (uint256); + + function truToUsd(uint256 amount) external view returns (uint256); } diff --git a/flatten/ITrueRatingAgencyV2.sol b/flatten/ITrueRatingAgencyV2.sol new file mode 100644 index 000000000..70bf272e7 --- /dev/null +++ b/flatten/ITrueRatingAgencyV2.sol @@ -0,0 +1,51 @@ +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +// Root file: contracts/truefi/interface/ITrueRatingAgencyV2.sol + +// SPDX-License-Identifier: MIT +pragma solidity 0.6.10; + +interface ITrueRatingAgencyV2 { + function getResults(address id) + external + view + returns ( + uint256, + uint256, + uint256 + ); + + function submit(address id) external; + + function retract(address id) external; + + function yes(address id) external; + + function no(address id) external; + + function claim(address id, address voter) external; +} diff --git a/flatten/LinearTrueDistributor.sol b/flatten/LinearTrueDistributor.sol index 10aed7ae8..df2c8b544 100644 --- a/flatten/LinearTrueDistributor.sol +++ b/flatten/LinearTrueDistributor.sol @@ -595,6 +595,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(); diff --git a/flatten/Liquidator.sol b/flatten/Liquidator.sol index 744625fa8..f14a4a181 100644 --- a/flatten/Liquidator.sol +++ b/flatten/Liquidator.sol @@ -273,6 +273,169 @@ interface IERC20 { } +// Dependency file: contracts/truefi/interface/ILoanToken.sol + +// pragma solidity 0.6.10; + +// import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +interface ILoanToken is IERC20 { + enum Status {Awaiting, Funded, Withdrawn, Settled, Defaulted, Liquidated} + + function borrower() external view returns (address); + + function amount() external view returns (uint256); + + function term() external view returns (uint256); + + function apy() external view returns (uint256); + + function start() external view returns (uint256); + + function lender() external view returns (address); + + function debt() external view returns (uint256); + + function profit() external view returns (uint256); + + function status() external view returns (Status); + + function borrowerFee() external view returns (uint256); + + function receivedAmount() external view returns (uint256); + + function isLoanToken() external pure returns (bool); + + function getParameters() + external + view + returns ( + uint256, + uint256, + uint256 + ); + + function fund() external; + + function withdraw(address _beneficiary) external; + + function close() external; + + function liquidate() external; + + function redeem(uint256 _amount) external; + + function repay(address _sender, uint256 _amount) external; + + function reclaim() external; + + function allowTransfer(address account, bool _status) external; + + function repaid() external view returns (uint256); + + function balance() external view returns (uint256); + + function value(uint256 _balance) external view returns (uint256); + + function currencyToken() external view returns (IERC20); + + function version() external pure returns (uint8); +} + + +// Dependency file: contracts/truefi/interface/ITrueFiPool.sol + +// pragma solidity 0.6.10; + +// import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +/** + * TruePool is an ERC20 which represents a share of a pool + * + * This contract can be used to wrap opportunities to be compatible + * with TrueFi and allow users to directly opt-in through the TUSD contract + * + * Each TruePool is also a staking opportunity for TRU + */ +interface ITrueFiPool is IERC20 { + /// @dev pool token (TUSD) + function currencyToken() external view returns (IERC20); + + /// @dev stake token (TRU) + function stakeToken() external view returns (IERC20); + + /** + * @dev join pool + * 1. Transfer TUSD from sender + * 2. Mint pool tokens based on value to sender + */ + function join(uint256 amount) external; + + /** + * @dev exit pool + * 1. Transfer pool tokens from sender + * 2. Burn pool tokens + * 3. Transfer value of pool tokens in TUSD to sender + */ + function exit(uint256 amount) external; + + /** + * @dev borrow from pool + * 1. Transfer TUSD to sender + * 2. Only lending pool should be allowed to call this + */ + function borrow(uint256 amount, uint256 fee) external; + + /** + * @dev join pool + * 1. Transfer TUSD from sender + * 2. Only lending pool should be allowed to call this + */ + function repay(uint256 amount) external; +} + + +// Dependency file: contracts/truefi/interface/IStakingPool.sol + +// pragma solidity 0.6.10; + +// import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +interface IStakingPool is IERC20 { + function stakeSupply() external view returns (uint256); + + function withdraw(uint256 amount) external; + + function payFee(uint256 amount, uint256 endTime) external; +} + + +// Dependency file: contracts/truefi/interface/ITruPriceOracle.sol + +// pragma solidity 0.6.10; + +interface ITruPriceOracle { + function usdToTru(uint256 amount) external view returns (uint256); + + function truToUsd(uint256 amount) external view returns (uint256); +} + + +// Dependency file: contracts/truefi/interface/ILoanFactory.sol + +// pragma solidity 0.6.10; + +interface ILoanFactory { + function createLoanToken( + uint256 _amount, + uint256 _term, + uint256 _apy + ) external; + + function isLoanToken(address) external view returns (bool); +} + + // Dependency file: @openzeppelin/contracts/math/SafeMath.sol @@ -435,1067 +598,12 @@ library SafeMath { } -// Dependency file: @openzeppelin/contracts/utils/Address.sol - - -// pragma solidity ^0.6.2; - -/** - * @dev Collection of functions related to the address type - */ -library Address { - /** - * @dev Returns true if `account` is a contract. - * - * [// importANT] - * ==== - * It is unsafe to assume that an address for which this function returns - * false is an externally-owned account (EOA) and not a contract. - * - * Among others, `isContract` will return false for the following - * types of addresses: - * - * - an externally-owned account - * - a contract in construction - * - an address where a contract will be created - * - an address where a contract lived, but was destroyed - * ==== - */ - function isContract(address account) internal view returns (bool) { - // This method relies in extcodesize, which returns 0 for contracts in - // construction, since the code is only stored at the end of the - // constructor execution. - - uint256 size; - // solhint-disable-next-line no-inline-assembly - assembly { size := extcodesize(account) } - return size > 0; - } - - /** - * @dev Replacement for Solidity's `transfer`: sends `amount` wei to - * `recipient`, forwarding all available gas and reverting on errors. - * - * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost - * of certain opcodes, possibly making contracts go over the 2300 gas limit - * imposed by `transfer`, making them unable to receive funds via - * `transfer`. {sendValue} removes this limitation. - * - * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. - * - * // importANT: because control is transferred to `recipient`, care must be - * taken to not create reentrancy vulnerabilities. Consider using - * {ReentrancyGuard} or the - * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. - */ - function sendValue(address payable recipient, uint256 amount) internal { - require(address(this).balance >= amount, "Address: insufficient balance"); - - // solhint-disable-next-line avoid-low-level-calls, avoid-call-value - (bool success, ) = recipient.call{ value: amount }(""); - require(success, "Address: unable to send value, recipient may have reverted"); - } - - /** - * @dev Performs a Solidity function call using a low level `call`. A - * plain`call` is an unsafe replacement for a function call: use this - * function instead. - * - * If `target` reverts with a revert reason, it is bubbled up by this - * function (like regular Solidity function calls). - * - * Returns the raw returned data. To convert to the expected return value, - * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. - * - * Requirements: - * - * - `target` must be a contract. - * - calling `target` with `data` must not revert. - * - * _Available since v3.1._ - */ - function functionCall(address target, bytes memory data) internal returns (bytes memory) { - return functionCall(target, data, "Address: low-level call failed"); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with - * `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { - return _functionCallWithValue(target, data, 0, errorMessage); - } - - /** - * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], - * but also transferring `value` wei to `target`. - * - * Requirements: - * - * - the calling contract must have an ETH balance of at least `value`. - * - the called Solidity function must be `payable`. - * - * _Available since v3.1._ - */ - function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { - return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); - } - - /** - * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but - * with `errorMessage` as a fallback revert reason when `target` reverts. - * - * _Available since v3.1._ - */ - function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { - require(address(this).balance >= value, "Address: insufficient balance for call"); - return _functionCallWithValue(target, data, value, errorMessage); - } - - function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { - require(isContract(target), "Address: call to non-contract"); - - // solhint-disable-next-line avoid-low-level-calls - (bool success, bytes memory returndata) = target.call{ value: weiValue }(data); - if (success) { - return returndata; - } else { - // Look for revert reason and bubble it up if present - if (returndata.length > 0) { - // The easiest way to bubble the revert reason is using memory via assembly - - // solhint-disable-next-line no-inline-assembly - assembly { - let returndata_size := mload(returndata) - revert(add(32, returndata), returndata_size) - } - } else { - revert(errorMessage); - } - } - } -} - - -// Dependency file: @openzeppelin/contracts/token/ERC20/ERC20.sol - - -// pragma solidity ^0.6.0; - -// import "@openzeppelin/contracts/GSN/Context.sol"; -// import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -// import "@openzeppelin/contracts/math/SafeMath.sol"; -// import "@openzeppelin/contracts/utils/Address.sol"; - -/** - * @dev Implementation of the {IERC20} interface. - * - * This implementation is agnostic to the way tokens are created. This means - * that a supply mechanism has to be added in a derived contract using {_mint}. - * For a generic mechanism see {ERC20PresetMinterPauser}. - * - * TIP: For a detailed writeup see our guide - * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How - * to implement supply mechanisms]. - * - * We have followed general OpenZeppelin guidelines: functions revert instead - * of returning `false` on failure. This behavior is nonetheless conventional - * and does not conflict with the expectations of ERC20 applications. - * - * Additionally, an {Approval} event is emitted on calls to {transferFrom}. - * This allows applications to reconstruct the allowance for all accounts just - * by listening to said events. Other implementations of the EIP may not emit - * these events, as it isn't required by the specification. - * - * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} - * functions have been added to mitigate the well-known issues around setting - * allowances. See {IERC20-approve}. - */ -contract ERC20 is Context, IERC20 { - using SafeMath for uint256; - using Address for address; - - mapping (address => uint256) private _balances; - - mapping (address => mapping (address => uint256)) private _allowances; - - uint256 private _totalSupply; - - string private _name; - string private _symbol; - uint8 private _decimals; - - /** - * @dev Sets the values for {name} and {symbol}, initializes {decimals} with - * a default value of 18. - * - * To select a different value for {decimals}, use {_setupDecimals}. - * - * All three of these values are immutable: they can only be set once during - * construction. - */ - constructor (string memory name, string memory symbol) public { - _name = name; - _symbol = symbol; - _decimals = 18; - } - - /** - * @dev Returns the name of the token. - */ - function name() public view returns (string memory) { - return _name; - } - - /** - * @dev Returns the symbol of the token, usually a shorter version of the - * name. - */ - function symbol() public view returns (string memory) { - return _symbol; - } +// Root file: contracts/truefi/Liquidator.sol - /** - * @dev Returns the number of decimals used to get its user representation. - * For example, if `decimals` equals `2`, a balance of `505` tokens should - * be displayed to a user as `5,05` (`505 / 10 ** 2`). - * - * Tokens usually opt for a value of 18, imitating the relationship between - * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is - * called. - * - * NOTE: This information is only used for _display_ purposes: it in - * no way affects any of the arithmetic of the contract, including - * {IERC20-balanceOf} and {IERC20-transfer}. - */ - function decimals() public view returns (uint8) { - return _decimals; - } - - /** - * @dev See {IERC20-totalSupply}. - */ - function totalSupply() public view override returns (uint256) { - return _totalSupply; - } - - /** - * @dev See {IERC20-balanceOf}. - */ - function balanceOf(address account) public view override returns (uint256) { - return _balances[account]; - } - - /** - * @dev See {IERC20-transfer}. - * - * Requirements: - * - * - `recipient` cannot be the zero address. - * - the caller must have a balance of at least `amount`. - */ - function transfer(address recipient, uint256 amount) public virtual override returns (bool) { - _transfer(_msgSender(), recipient, amount); - return true; - } - - /** - * @dev See {IERC20-allowance}. - */ - function allowance(address owner, address spender) public view virtual override returns (uint256) { - return _allowances[owner][spender]; - } - - /** - * @dev See {IERC20-approve}. - * - * Requirements: - * - * - `spender` cannot be the zero address. - */ - function approve(address spender, uint256 amount) public virtual override returns (bool) { - _approve(_msgSender(), spender, amount); - return true; - } - - /** - * @dev See {IERC20-transferFrom}. - * - * Emits an {Approval} event indicating the updated allowance. This is not - * required by the EIP. See the note at the beginning of {ERC20}; - * - * Requirements: - * - `sender` and `recipient` cannot be the zero address. - * - `sender` must have a balance of at least `amount`. - * - the caller must have allowance for ``sender``'s tokens of at least - * `amount`. - */ - function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { - _transfer(sender, recipient, amount); - _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); - return true; - } - - /** - * @dev Atomically increases the allowance granted to `spender` by the caller. - * - * This is an alternative to {approve} that can be used as a mitigation for - * problems described in {IERC20-approve}. - * - * Emits an {Approval} event indicating the updated allowance. - * - * Requirements: - * - * - `spender` cannot be the zero address. - */ - function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { - _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); - return true; - } - - /** - * @dev Atomically decreases the allowance granted to `spender` by the caller. - * - * This is an alternative to {approve} that can be used as a mitigation for - * problems described in {IERC20-approve}. - * - * Emits an {Approval} event indicating the updated allowance. - * - * Requirements: - * - * - `spender` cannot be the zero address. - * - `spender` must have allowance for the caller of at least - * `subtractedValue`. - */ - function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { - _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); - return true; - } - - /** - * @dev Moves tokens `amount` from `sender` to `recipient`. - * - * This is internal function is equivalent to {transfer}, and can be used to - * e.g. implement automatic token fees, slashing mechanisms, etc. - * - * Emits a {Transfer} event. - * - * Requirements: - * - * - `sender` cannot be the zero address. - * - `recipient` cannot be the zero address. - * - `sender` must have a balance of at least `amount`. - */ - function _transfer(address sender, address recipient, uint256 amount) internal virtual { - require(sender != address(0), "ERC20: transfer from the zero address"); - require(recipient != address(0), "ERC20: transfer to the zero address"); - - _beforeTokenTransfer(sender, recipient, amount); - - _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); - _balances[recipient] = _balances[recipient].add(amount); - emit Transfer(sender, recipient, amount); - } - - /** @dev Creates `amount` tokens and assigns them to `account`, increasing - * the total supply. - * - * Emits a {Transfer} event with `from` set to the zero address. - * - * Requirements - * - * - `to` cannot be the zero address. - */ - function _mint(address account, uint256 amount) internal virtual { - require(account != address(0), "ERC20: mint to the zero address"); - - _beforeTokenTransfer(address(0), account, amount); - - _totalSupply = _totalSupply.add(amount); - _balances[account] = _balances[account].add(amount); - emit Transfer(address(0), account, amount); - } - - /** - * @dev Destroys `amount` tokens from `account`, reducing the - * total supply. - * - * Emits a {Transfer} event with `to` set to the zero address. - * - * Requirements - * - * - `account` cannot be the zero address. - * - `account` must have at least `amount` tokens. - */ - function _burn(address account, uint256 amount) internal virtual { - require(account != address(0), "ERC20: burn from the zero address"); - - _beforeTokenTransfer(account, address(0), amount); - - _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); - _totalSupply = _totalSupply.sub(amount); - emit Transfer(account, address(0), amount); - } - - /** - * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. - * - * This internal function is equivalent to `approve`, and can be used to - * e.g. set automatic allowances for certain subsystems, etc. - * - * Emits an {Approval} event. - * - * Requirements: - * - * - `owner` cannot be the zero address. - * - `spender` cannot be the zero address. - */ - function _approve(address owner, address spender, uint256 amount) internal virtual { - require(owner != address(0), "ERC20: approve from the zero address"); - require(spender != address(0), "ERC20: approve to the zero address"); - - _allowances[owner][spender] = amount; - emit Approval(owner, spender, amount); - } - - /** - * @dev Sets {decimals} to a value other than the default one of 18. - * - * WARNING: This function should only be called from the constructor. Most - * applications that interact with token contracts will not expect - * {decimals} to ever change, and may work incorrectly if it does. - */ - function _setupDecimals(uint8 decimals_) internal { - _decimals = decimals_; - } - - /** - * @dev Hook that is called before any transfer of tokens. This includes - * minting and burning. - * - * Calling conditions: - * - * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens - * will be to transferred to `to`. - * - when `from` is zero, `amount` tokens will be minted for `to`. - * - when `to` is zero, `amount` of ``from``'s tokens will be burned. - * - `from` and `to` are never both zero. - * - * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. - */ - function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } -} - - -// Dependency file: contracts/truefi/interface/ILoanToken.sol - -// pragma solidity 0.6.10; - -// import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -interface ILoanToken is IERC20 { - enum Status {Awaiting, Funded, Withdrawn, Settled, Defaulted, Liquidated} - - function borrower() external view returns (address); - - function amount() external view returns (uint256); - - function term() external view returns (uint256); - - function apy() external view returns (uint256); - - function start() external view returns (uint256); - - function lender() external view returns (address); - - function debt() external view returns (uint256); - - function profit() external view returns (uint256); - - function status() external view returns (Status); - - function borrowerFee() external view returns (uint256); - - function receivedAmount() external view returns (uint256); - - function isLoanToken() external pure returns (bool); - - function getParameters() - external - view - returns ( - uint256, - uint256, - uint256 - ); - - function fund() external; - - function withdraw(address _beneficiary) external; - - function close() external; - - function liquidate() external; - - function redeem(uint256 _amount) external; - - function repay(address _sender, uint256 _amount) external; - - function reclaim() external; - - function allowTransfer(address account, bool _status) external; - - function repaid() external view returns (uint256); - - function balance() external view returns (uint256); - - function value(uint256 _balance) external view returns (uint256); - - function currencyToken() external view returns (IERC20); - - function version() external pure returns (uint8); -} - - -// Dependency file: contracts/truefi/LoanToken.sol - -// pragma solidity 0.6.10; - -// import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -// import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -// import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; - -// import {ILoanToken} from "contracts/truefi/interface/ILoanToken.sol"; - -/** - * @title LoanToken - * @dev A token which represents share of a debt obligation - * - * Each LoanToken has: - * - borrower address - * - borrow amount - * - loan term - * - loan APY - * - * Loan progresses through the following states: - * Awaiting: Waiting for funding to meet capital requirements - * Funded: Capital requirements met, borrower can withdraw - * Withdrawn: Borrower withdraws money, loan waiting to be repaid - * Settled: Loan has been paid back in full with interest - * Defaulted: Loan has not been paid back in full - * - * - LoanTokens are non-transferable except for whitelisted addresses - * - This version of LoanToken only supports a single funder - */ -contract LoanToken is ILoanToken, ERC20 { - using SafeMath for uint256; - - uint128 public constant lastMinutePaybackDuration = 1 days; - uint8 public constant override version = 3; - - address public override borrower; - address public liquidator; - uint256 public override amount; - uint256 public override term; - uint256 public override apy; - - uint256 public override start; - address public override lender; - uint256 public override debt; - - uint256 public redeemed; - - // borrow fee -> 25 = 0.25% - uint256 public override borrowerFee = 25; - - // whitelist for transfers - mapping(address => bool) public canTransfer; - - Status public override status; - - IERC20 public override currencyToken; - - /** - * @dev Emitted when the loan is funded - * @param lender Address which funded the loan - */ - event Funded(address lender); - - /** - * @dev Emitted when transfer whitelist is updated - * @param account Account to whitelist for transfers - * @param status New whitelist status - */ - event TransferAllowanceChanged(address account, bool status); - - /** - * @dev Emitted when borrower withdraws funds - * @param beneficiary Account which will receive funds - */ - event Withdrawn(address beneficiary); - - /** - * @dev Emitted when term is over - * @param status Final loan status - * @param returnedAmount Amount that was retured before expiry - */ - event Closed(Status status, uint256 returnedAmount); - - /** - * @dev Emitted when a LoanToken is redeemed for underlying currencyTokens - * @param receiver Receiver of currencyTokens - * @param burnedAmount Amount of LoanTokens burned - * @param redeemedAmound Amount of currencyToken received - */ - event Redeemed(address receiver, uint256 burnedAmount, uint256 redeemedAmound); - - /** - * @dev Emitted when a LoanToken is repaid by the borrower in underlying currencyTokens - * @param repayer Sender of currencyTokens - * @param repaidAmound Amount of currencyToken repaid - */ - event Repaid(address repayer, uint256 repaidAmound); - - /** - * @dev Emitted when borrower reclaims remaining currencyTokens - * @param borrower Reveiver of remaining currencyTokens - * @param reclaimedAmount Amount of currencyTokens repaid - */ - event Reclaimed(address borrower, uint256 reclaimedAmount); - - /** - * @dev Emitted when loan gets liquidated - * @param status Final loan status - */ - event Liquidated(Status status); - - /** - * @dev Create a Loan - * @param _currencyToken Token to lend - * @param _borrower Borrwer addresss - * @param _amount Borrow amount of currency tokens - * @param _term Loan length - * @param _apy Loan APY - */ - constructor( - IERC20 _currencyToken, - address _borrower, - address _lender, - address _liquidator, - uint256 _amount, - uint256 _term, - uint256 _apy - ) public ERC20("Loan Token", "LOAN") { - require(_lender != address(0), "LoanToken: Lender is not set"); - - currencyToken = _currencyToken; - borrower = _borrower; - liquidator = _liquidator; - amount = _amount; - term = _term; - apy = _apy; - lender = _lender; - debt = interest(amount); - } - - /** - * @dev Only borrower can withdraw & repay loan - */ - modifier onlyBorrower() { - require(msg.sender == borrower, "LoanToken: Caller is not the borrower"); - _; - } - - /** - * @dev Only liquidator can liquidate - */ - modifier onlyLiquidator() { - require(msg.sender == liquidator, "LoanToken: Caller is not the liquidator"); - _; - } - - /** - * @dev Only when loan is Settled - */ - modifier onlyClosed() { - require(status >= Status.Settled, "LoanToken: Current status should be Settled or Defaulted"); - _; - } - - /** - * @dev Only when loan is Funded - */ - modifier onlyOngoing() { - require(status == Status.Funded || status == Status.Withdrawn, "LoanToken: Current status should be Funded or Withdrawn"); - _; - } - - /** - * @dev Only when loan is Funded - */ - modifier onlyFunded() { - require(status == Status.Funded, "LoanToken: Current status should be Funded"); - _; - } - - /** - * @dev Only when loan is Withdrawn - */ - modifier onlyAfterWithdraw() { - require(status >= Status.Withdrawn, "LoanToken: Only after loan has been withdrawn"); - _; - } - - /** - * @dev Only when loan is Awaiting - */ - modifier onlyAwaiting() { - require(status == Status.Awaiting, "LoanToken: Current status should be Awaiting"); - _; - } - - /** - * @dev Only when loan is Defaulted - */ - modifier onlyDefaulted() { - require(status == Status.Defaulted, "LoanToken: Current status should be Defaulted"); - _; - } - - /** - * @dev Only whitelisted accounts or lender - */ - modifier onlyWhoCanTransfer(address sender) { - require( - sender == lender || canTransfer[sender], - "LoanToken: This can be performed only by lender or accounts allowed to transfer" - ); - _; - } - - /** - * @dev Only lender can perform certain actions - */ - modifier onlyLender() { - require(msg.sender == lender, "LoanToken: This can be performed only by lender"); - _; - } - - /** - * @dev Return true if this contract is a LoanToken - * @return True if this contract is a LoanToken - */ - function isLoanToken() external override pure returns (bool) { - return true; - } - - /** - * @dev Get loan parameters - * @return amount, term, apy - */ - function getParameters() - external - override - view - returns ( - uint256, - uint256, - uint256 - ) - { - return (amount, apy, term); - } - - /** - * @dev Get coupon value of this loan token in currencyToken - * This assumes the loan will be paid back on time, with interest - * @param _balance number of LoanTokens to get value for - * @return coupon value of _balance LoanTokens in currencyTokens - */ - function value(uint256 _balance) external override view returns (uint256) { - if (_balance == 0) { - return 0; - } - - uint256 passed = block.timestamp.sub(start); - if (passed > term) { - passed = term; - } - - // assume year is 365 days - uint256 interest = amount.mul(apy).mul(passed).div(365 days).div(10000); - - return amount.add(interest).mul(_balance).div(debt); - } - - /** - * @dev Fund a loan - * Set status, start time, lender - */ - function fund() external override onlyAwaiting onlyLender { - status = Status.Funded; - start = block.timestamp; - _mint(msg.sender, debt); - require(currencyToken.transferFrom(msg.sender, address(this), receivedAmount())); - - emit Funded(msg.sender); - } - - /** - * @dev Whitelist accounts to transfer - * @param account address to allow transfers for - * @param _status true allows transfers, false disables transfers - */ - function allowTransfer(address account, bool _status) external override onlyLender { - canTransfer[account] = _status; - emit TransferAllowanceChanged(account, _status); - } - - /** - * @dev Borrower calls this function to withdraw funds - * Sets the status of the loan to Withdrawn - * @param _beneficiary address to send funds to - */ - function withdraw(address _beneficiary) external override onlyBorrower onlyFunded { - status = Status.Withdrawn; - require(currencyToken.transfer(_beneficiary, receivedAmount())); - - emit Withdrawn(_beneficiary); - } - - /** - * @dev Close the loan and check if it has been repaid - */ - function close() external override onlyOngoing { - require(start.add(term) <= block.timestamp, "LoanToken: Loan cannot be closed yet"); - if (_balance() >= debt) { - status = Status.Settled; - } else { - require( - start.add(term).add(lastMinutePaybackDuration) <= block.timestamp, - "LoanToken: Borrower can still pay the loan back" - ); - status = Status.Defaulted; - } - - emit Closed(status, _balance()); - } - - /** - * @dev Liquidate the loan if it has defaulted - */ - function liquidate() external override onlyDefaulted onlyLiquidator { - status = Status.Liquidated; - - emit Liquidated(status); - } - - /** - * @dev Redeem LoanToken balances for underlying currencyToken - * Can only call this function after the loan is Closed - * @param _amount amount to redeem - */ - function redeem(uint256 _amount) external override onlyClosed { - uint256 amountToReturn = _amount.mul(_balance()).div(totalSupply()); - redeemed = redeemed.add(amountToReturn); - _burn(msg.sender, _amount); - require(currencyToken.transfer(msg.sender, amountToReturn)); - - emit Redeemed(msg.sender, _amount, amountToReturn); - } - - /** - * @dev Function for borrower to repay the loan - * Borrower can repay at any time - * @param _sender account sending currencyToken to repay - * @param _amount amount of currencyToken to repay - */ - function repay(address _sender, uint256 _amount) external override onlyAfterWithdraw { - require(_amount <= debt.sub(_balance()), "LoanToken: Cannot repay over the debt"); - require(currencyToken.transferFrom(_sender, address(this), _amount)); - emit Repaid(_sender, _amount); - } - - /** - * @dev Function for borrower to reclaim stuck currencyToken - * Can only call this function after the loan is Closed - * and all of LoanToken holders have been burnt - */ - function reclaim() external override onlyClosed onlyBorrower { - require(totalSupply() == 0, "LoanToken: Cannot reclaim when LoanTokens are in circulation"); - uint256 balanceRemaining = _balance(); - require(balanceRemaining > 0, "LoanToken: Cannot reclaim when balance 0"); - - require(currencyToken.transfer(borrower, balanceRemaining)); - emit Reclaimed(borrower, balanceRemaining); - } - - /** - * @dev Check how much was already repaid - * Funds stored on the contract's addres plus funds already redeemed by lenders - * @return Uint256 representing what value was already repaid - */ - function repaid() external override view onlyAfterWithdraw returns (uint256) { - return _balance().add(redeemed); - } - - /** - * @dev Public currency token balance function - * @return currencyToken balance of this contract - */ - function balance() external override view returns (uint256) { - return _balance(); - } - - /** - * @dev Get currency token balance for this contract - * @return currencyToken balance of this contract - */ - function _balance() internal view returns (uint256) { - return currencyToken.balanceOf(address(this)); - } - - /** - * @dev Calculate amount borrowed minus fee - * @return Amount minus fees - */ - function receivedAmount() public override view returns (uint256) { - return amount.sub(amount.mul(borrowerFee).div(10000)); - } - - /** - * @dev Calculate interest that will be paid by this loan for an amount (returned funds included) - * amount + ((amount * apy * term) / (365 days / precision)) - * @param _amount amount - * @return uint256 Amount of interest paid for _amount - */ - function interest(uint256 _amount) internal view returns (uint256) { - return _amount.add(_amount.mul(apy).mul(term).div(365 days).div(10000)); - } - - /** - * @dev get profit for this loan - * @return profit for this loan - */ - function profit() external override view returns (uint256) { - return debt.sub(amount); - } - - /** - * @dev Override ERC20 _transfer so only whitelisted addresses can transfer - * @param sender sender of the transaction - * @param recipient recipient of the transaction - * @param _amount amount to send - */ - function _transfer( - address sender, - address recipient, - uint256 _amount - ) internal override onlyWhoCanTransfer(sender) { - return super._transfer(sender, recipient, _amount); - } -} - - -// Dependency file: contracts/truefi/interface/ITrueFiPool.sol - -// pragma solidity 0.6.10; - -// import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -/** - * TruePool is an ERC20 which represents a share of a pool - * - * This contract can be used to wrap opportunities to be compatible - * with TrueFi and allow users to directly opt-in through the TUSD contract - * - * Each TruePool is also a staking opportunity for TRU - */ -interface ITrueFiPool is IERC20 { - /// @dev pool token (TUSD) - function currencyToken() external view returns (IERC20); - - /// @dev stake token (TRU) - function stakeToken() external view returns (IERC20); - - /** - * @dev join pool - * 1. Transfer TUSD from sender - * 2. Mint pool tokens based on value to sender - */ - function join(uint256 amount) external; - - /** - * @dev exit pool - * 1. Transfer pool tokens from sender - * 2. Burn pool tokens - * 3. Transfer value of pool tokens in TUSD to sender - */ - function exit(uint256 amount) external; - - /** - * @dev borrow from pool - * 1. Transfer TUSD to sender - * 2. Only lending pool should be allowed to call this - */ - function borrow(uint256 amount, uint256 fee) external; - - /** - * @dev join pool - * 1. Transfer TUSD from sender - * 2. Only lending pool should be allowed to call this - */ - function repay(uint256 amount) external; -} - - -// Dependency file: contracts/truefi/interface/IStakingPool.sol - -// pragma solidity 0.6.10; - -// import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -interface IStakingPool is IERC20 { - function stakeSupply() external view returns (uint256); - - function withdraw(uint256 amount) external; - - function payFee(uint256 amount, uint256 endTime) external; -} - - -// Dependency file: contracts/truefi/interface/ITruPriceOracle.sol - -// pragma solidity 0.6.10; - -interface ITruPriceOracle { - function usdToTru(uint256 amount) external view returns (uint256); -} - - -// Dependency file: contracts/truefi/interface/ILoanFactory.sol - -// pragma solidity 0.6.10; - -interface ILoanFactory { - function createLoanToken( - uint256 _amount, - uint256 _term, - uint256 _apy - ) external; - - function isLoanToken(address) external view returns (bool); -} - - -// Root file: contracts/truefi/Liquidator.sol - -pragma solidity 0.6.10; +pragma solidity 0.6.10; // import {Ownable} from "contracts/truefi/common/UpgradeableOwnable.sol"; -// import {LoanToken, IERC20} from "contracts/truefi/LoanToken.sol"; +// import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; // import {ILoanToken} from "contracts/truefi/interface/ILoanToken.sol"; // import {ITrueFiPool} from "contracts/truefi/interface/ITrueFiPool.sol"; @@ -1575,12 +683,14 @@ contract Liquidator is Ownable { */ function setFetchMaxShare(uint256 newShare) external onlyOwner { require(newShare > 0, "Liquidator: Share cannot be set to 0"); + require(newShare <= 10000, "Liquidator: Share cannot be larger than 10000"); fetchMaxShare = newShare; emit FetchMaxShareChanged(newShare); } /** * @dev Change oracle + * @param newOracle New oracle for liquidator */ function setOracle(ITruPriceOracle newOracle) external onlyOwner { // Check if new oracle implements method @@ -1600,6 +710,7 @@ contract Liquidator is Ownable { require(factory.isLoanToken(address(loan)), "Liquidator: Unknown loan"); uint256 defaultedValue = getAmountToWithdraw(loan.debt().sub(loan.repaid())); stkTru.withdraw(defaultedValue); + require(loan.status() == ILoanToken.Status.Defaulted, "Liquidator: Loan must be defaulted"); loan.liquidate(); require(tru.transfer(address(pool), defaultedValue)); emit Liquidated(loan); @@ -1608,6 +719,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/flatten/LoanFactory.sol b/flatten/LoanFactory.sol index 22aadec34..811b69b5d 100644 --- a/flatten/LoanFactory.sol +++ b/flatten/LoanFactory.sol @@ -927,6 +927,7 @@ interface ILoanToken is IERC20 { * Withdrawn: Borrower withdraws money, loan waiting to be repaid * Settled: Loan has been paid back in full with interest * Defaulted: Loan has not been paid back in full + * Liquidated: Loan has Defaulted and stakers have been Liquidated * * - LoanTokens are non-transferable except for whitelisted addresses * - This version of LoanToken only supports a single funder @@ -981,7 +982,7 @@ contract LoanToken is ILoanToken, ERC20 { /** * @dev Emitted when term is over * @param status Final loan status - * @param returnedAmount Amount that was retured before expiry + * @param returnedAmount Amount that was returned before expiry */ event Closed(Status status, uint256 returnedAmount); @@ -989,20 +990,20 @@ contract LoanToken is ILoanToken, ERC20 { * @dev Emitted when a LoanToken is redeemed for underlying currencyTokens * @param receiver Receiver of currencyTokens * @param burnedAmount Amount of LoanTokens burned - * @param redeemedAmound Amount of currencyToken received + * @param redeemedAmount Amount of currencyToken received */ - event Redeemed(address receiver, uint256 burnedAmount, uint256 redeemedAmound); + event Redeemed(address receiver, uint256 burnedAmount, uint256 redeemedAmount); /** * @dev Emitted when a LoanToken is repaid by the borrower in underlying currencyTokens * @param repayer Sender of currencyTokens - * @param repaidAmound Amount of currencyToken repaid + * @param repaidAmount Amount of currencyToken repaid */ - event Repaid(address repayer, uint256 repaidAmound); + event Repaid(address repayer, uint256 repaidAmount); /** * @dev Emitted when borrower reclaims remaining currencyTokens - * @param borrower Reveiver of remaining currencyTokens + * @param borrower Receiver of remaining currencyTokens * @param reclaimedAmount Amount of currencyTokens repaid */ event Reclaimed(address borrower, uint256 reclaimedAmount); @@ -1016,7 +1017,7 @@ contract LoanToken is ILoanToken, ERC20 { /** * @dev Create a Loan * @param _currencyToken Token to lend - * @param _borrower Borrwer addresss + * @param _borrower Borrower address * @param _amount Borrow amount of currency tokens * @param _term Loan length * @param _apy Loan APY @@ -1276,7 +1277,7 @@ contract LoanToken is ILoanToken, ERC20 { /** * @dev Check how much was already repaid - * Funds stored on the contract's addres plus funds already redeemed by lenders + * Funds stored on the contract's address plus funds already redeemed by lenders * @return Uint256 representing what value was already repaid */ function repaid() external override view onlyAfterWithdraw returns (uint256) { @@ -1387,12 +1388,14 @@ contract LoanFactory is ILoanFactory, Initializable { currencyToken = _currencyToken; } + /** @dev sets lender address **/ function setLender() external { lender = 0x16d02Dc67EB237C387023339356b25d1D54b0922; } + /** @dev sets liquidator address **/ function setLiquidator() external { - liquidator = address(0); // to be changed for deployment + liquidator = 0x76dd4921C99AC6b61b3a98f9fa6f181cA6D70c77; } /** diff --git a/flatten/LoanToken.sol b/flatten/LoanToken.sol index 50c55a698..df2211947 100644 --- a/flatten/LoanToken.sol +++ b/flatten/LoanToken.sol @@ -844,6 +844,7 @@ pragma solidity 0.6.10; * Withdrawn: Borrower withdraws money, loan waiting to be repaid * Settled: Loan has been paid back in full with interest * Defaulted: Loan has not been paid back in full + * Liquidated: Loan has Defaulted and stakers have been Liquidated * * - LoanTokens are non-transferable except for whitelisted addresses * - This version of LoanToken only supports a single funder @@ -898,7 +899,7 @@ contract LoanToken is ILoanToken, ERC20 { /** * @dev Emitted when term is over * @param status Final loan status - * @param returnedAmount Amount that was retured before expiry + * @param returnedAmount Amount that was returned before expiry */ event Closed(Status status, uint256 returnedAmount); @@ -906,20 +907,20 @@ contract LoanToken is ILoanToken, ERC20 { * @dev Emitted when a LoanToken is redeemed for underlying currencyTokens * @param receiver Receiver of currencyTokens * @param burnedAmount Amount of LoanTokens burned - * @param redeemedAmound Amount of currencyToken received + * @param redeemedAmount Amount of currencyToken received */ - event Redeemed(address receiver, uint256 burnedAmount, uint256 redeemedAmound); + event Redeemed(address receiver, uint256 burnedAmount, uint256 redeemedAmount); /** * @dev Emitted when a LoanToken is repaid by the borrower in underlying currencyTokens * @param repayer Sender of currencyTokens - * @param repaidAmound Amount of currencyToken repaid + * @param repaidAmount Amount of currencyToken repaid */ - event Repaid(address repayer, uint256 repaidAmound); + event Repaid(address repayer, uint256 repaidAmount); /** * @dev Emitted when borrower reclaims remaining currencyTokens - * @param borrower Reveiver of remaining currencyTokens + * @param borrower Receiver of remaining currencyTokens * @param reclaimedAmount Amount of currencyTokens repaid */ event Reclaimed(address borrower, uint256 reclaimedAmount); @@ -933,7 +934,7 @@ contract LoanToken is ILoanToken, ERC20 { /** * @dev Create a Loan * @param _currencyToken Token to lend - * @param _borrower Borrwer addresss + * @param _borrower Borrower address * @param _amount Borrow amount of currency tokens * @param _term Loan length * @param _apy Loan APY @@ -1193,7 +1194,7 @@ contract LoanToken is ILoanToken, ERC20 { /** * @dev Check how much was already repaid - * Funds stored on the contract's addres plus funds already redeemed by lenders + * Funds stored on the contract's address plus funds already redeemed by lenders * @return Uint256 representing what value was already repaid */ function repaid() external override view onlyAfterWithdraw returns (uint256) { diff --git a/flatten/MockLoanFactory.sol b/flatten/MockLoanFactory.sol index 0864e478d..4e0032228 100644 --- a/flatten/MockLoanFactory.sol +++ b/flatten/MockLoanFactory.sol @@ -927,6 +927,7 @@ interface ILoanToken is IERC20 { * Withdrawn: Borrower withdraws money, loan waiting to be repaid * Settled: Loan has been paid back in full with interest * Defaulted: Loan has not been paid back in full + * Liquidated: Loan has Defaulted and stakers have been Liquidated * * - LoanTokens are non-transferable except for whitelisted addresses * - This version of LoanToken only supports a single funder @@ -981,7 +982,7 @@ contract LoanToken is ILoanToken, ERC20 { /** * @dev Emitted when term is over * @param status Final loan status - * @param returnedAmount Amount that was retured before expiry + * @param returnedAmount Amount that was returned before expiry */ event Closed(Status status, uint256 returnedAmount); @@ -989,20 +990,20 @@ contract LoanToken is ILoanToken, ERC20 { * @dev Emitted when a LoanToken is redeemed for underlying currencyTokens * @param receiver Receiver of currencyTokens * @param burnedAmount Amount of LoanTokens burned - * @param redeemedAmound Amount of currencyToken received + * @param redeemedAmount Amount of currencyToken received */ - event Redeemed(address receiver, uint256 burnedAmount, uint256 redeemedAmound); + event Redeemed(address receiver, uint256 burnedAmount, uint256 redeemedAmount); /** * @dev Emitted when a LoanToken is repaid by the borrower in underlying currencyTokens * @param repayer Sender of currencyTokens - * @param repaidAmound Amount of currencyToken repaid + * @param repaidAmount Amount of currencyToken repaid */ - event Repaid(address repayer, uint256 repaidAmound); + event Repaid(address repayer, uint256 repaidAmount); /** * @dev Emitted when borrower reclaims remaining currencyTokens - * @param borrower Reveiver of remaining currencyTokens + * @param borrower Receiver of remaining currencyTokens * @param reclaimedAmount Amount of currencyTokens repaid */ event Reclaimed(address borrower, uint256 reclaimedAmount); @@ -1016,7 +1017,7 @@ contract LoanToken is ILoanToken, ERC20 { /** * @dev Create a Loan * @param _currencyToken Token to lend - * @param _borrower Borrwer addresss + * @param _borrower Borrower address * @param _amount Borrow amount of currency tokens * @param _term Loan length * @param _apy Loan APY @@ -1276,7 +1277,7 @@ contract LoanToken is ILoanToken, ERC20 { /** * @dev Check how much was already repaid - * Funds stored on the contract's addres plus funds already redeemed by lenders + * Funds stored on the contract's address plus funds already redeemed by lenders * @return Uint256 representing what value was already repaid */ function repaid() external override view onlyAfterWithdraw returns (uint256) { @@ -1387,12 +1388,14 @@ contract LoanFactory is ILoanFactory, Initializable { currencyToken = _currencyToken; } + /** @dev sets lender address **/ function setLender() external { lender = 0x16d02Dc67EB237C387023339356b25d1D54b0922; } + /** @dev sets liquidator address **/ function setLiquidator() external { - liquidator = address(0); // to be changed for deployment + liquidator = 0x76dd4921C99AC6b61b3a98f9fa6f181cA6D70c77; } /** diff --git a/flatten/MockOracle.sol b/flatten/MockOracle.sol index 2545bfd39..e131f01a5 100644 --- a/flatten/MockOracle.sol +++ b/flatten/MockOracle.sol @@ -23,6 +23,292 @@ ............... */ +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + // https://github.com/trusttoken/smart-contracts // Dependency file: contracts/governance/interface/ITruPriceOracle.sol diff --git a/flatten/MockStakingPool.sol b/flatten/MockStakingPool.sol index bac8a1c4b..99531167b 100644 --- a/flatten/MockStakingPool.sol +++ b/flatten/MockStakingPool.sol @@ -834,6 +834,11 @@ contract ERC20 is Initializable, Context, IERC20 { address to, uint256 amount ) internal virtual {} + + function updateNameAndSymbol(string memory __name, string memory __symbol) internal { + _name = __name; + _symbol = __symbol; + } } diff --git a/flatten/MockTruPriceOracle.sol b/flatten/MockTruPriceOracle.sol index 0fae6fb55..5363ae4a2 100644 --- a/flatten/MockTruPriceOracle.sol +++ b/flatten/MockTruPriceOracle.sol @@ -31,6 +31,8 @@ interface ITruPriceOracle { function usdToTru(uint256 amount) external view returns (uint256); + + function truToUsd(uint256 amount) external view returns (uint256); } @@ -41,8 +43,11 @@ pragma solidity 0.6.10; // import "contracts/truefi/interface/ITruPriceOracle.sol"; contract MockTruPriceOracle is ITruPriceOracle { - //from tusd to tru function usdToTru(uint256 amount) external override view returns (uint256) { return (amount * 4) / 1e10; } + + function truToUsd(uint256 amount) external override view returns (uint256) { + return (amount * 1e10) / 4; + } } diff --git a/flatten/MockTrueLender.sol b/flatten/MockTrueLender.sol index d49b6a35a..4c40dd01e 100644 --- a/flatten/MockTrueLender.sol +++ b/flatten/MockTrueLender.sol @@ -773,6 +773,12 @@ contract TrueLender is ITrueLender, Ownable { */ event Reclaimed(address indexed loanToken, uint256 amount); + /** + * @dev Emitted when rating agency contract is changed + * @param newRatingAgency Address of new rating agency + */ + event RatingAgencyChanged(address newRatingAgency); + /** * @dev Modifier for only lending pool */ @@ -895,6 +901,15 @@ contract TrueLender is ITrueLender, Ownable { emit LoansLimitChanged(maxLoans); } + /** + * @dev Set new rating agency. Only owner can change parameters. + * @param newRatingAgency New rating agency. + */ + function setRatingAgency(ITrueRatingAgency newRatingAgency) external onlyOwner { + ratingAgency = newRatingAgency; + emit RatingAgencyChanged(address(newRatingAgency)); + } + /** * @dev Get currently funded loans * @return result Array of loans currently funded @@ -937,6 +952,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)); @@ -950,7 +967,7 @@ contract TrueLender is ITrueLender, Ownable { } uint256 helper = loan.amount().mul(loan.apy()).mul(passed).mul(_balance); - // assume month is 30 days + // assume year is 365 days uint256 interest = helper.div(365 days).div(10000).div(loan.debt()); return loan.amount().mul(_balance).div(loan.debt()).add(interest); @@ -971,7 +988,7 @@ contract TrueLender is ITrueLender, Ownable { /** * @dev For settled loans, redeem LoanTokens for underlying funds - * @param loanToken Loan to reclaim capital from + * @param loanToken Loan to reclaim capital from (must be previously funded) */ function reclaim(ILoanToken loanToken) external { require(loanToken.isLoanToken(), "TrueLender: Only LoanTokens can be used to reclaimed"); @@ -997,11 +1014,14 @@ contract TrueLender is ITrueLender, Ownable { if (_loans[index] == loanToken) { _loans[index] = _loans[_loans.length - 1]; _loans.pop(); - break; + + emit Reclaimed(address(loanToken), fundsReclaimed); + return; } } - - emit Reclaimed(address(loanToken), fundsReclaimed); + // 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/flatten/RatingAgencyV2Distributor.sol b/flatten/RatingAgencyV2Distributor.sol new file mode 100644 index 000000000..8dfca517c --- /dev/null +++ b/flatten/RatingAgencyV2Distributor.sol @@ -0,0 +1,545 @@ +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +// Dependency file: @openzeppelin/contracts/token/ERC20/IERC20.sol + +// SPDX-License-Identifier: MIT + +// pragma solidity ^0.6.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address recipient, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * // importANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); + + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); +} + + +// Dependency file: @openzeppelin/contracts/math/SafeMath.sol + + +// pragma solidity ^0.6.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + return sub(a, b, "SafeMath: subtraction overflow"); + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + uint256 c = a - b; + + return c; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) { + return 0; + } + + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return div(a, b, "SafeMath: division by zero"); + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts with custom message on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + + return c; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + return mod(a, b, "SafeMath: modulo by zero"); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts with custom message when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b != 0, errorMessage); + return a % b; + } +} + + +// Dependency file: @openzeppelin/contracts/GSN/Context.sol + + +// pragma solidity ^0.6.0; + +/* + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with GSN meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address payable) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes memory) { + this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 + return msg.data; + } +} + + +// Dependency file: contracts/truefi/common/Initializable.sol + +// Copied from https://github.com/OpenZeppelin/openzeppelin-contracts-ethereum-package/blob/v3.0.0/contracts/Initializable.sol + +// pragma solidity 0.6.10; + +/** + * @title Initializable + * + * @dev Helper contract to support initializer functions. To use it, replace + * the constructor with a function that has the `initializer` modifier. + * WARNING: Unlike constructors, initializer functions must be manually + * invoked. This applies both to deploying an Initializable contract, as well + * as extending an Initializable contract via inheritance. + * WARNING: When used with inheritance, manual care must be taken to not invoke + * a parent initializer twice, or ensure that all initializers are idempotent, + * because this is not dealt with automatically as with constructors. + */ +contract Initializable { + /** + * @dev Indicates that the contract has been initialized. + */ + bool private initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private initializing; + + /** + * @dev Modifier to use in the initializer function of a contract. + */ + modifier initializer() { + require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); + + bool isTopLevelCall = !initializing; + if (isTopLevelCall) { + initializing = true; + initialized = true; + } + + _; + + if (isTopLevelCall) { + initializing = false; + } + } + + /// @dev Returns true if and only if the function is running in the constructor + function isConstructor() private view returns (bool) { + // extcodesize checks the size of the code stored in an address, and + // address returns the current address. Since the code is still not + // deployed when running a constructor, any checks on its code size will + // yield zero, making it an effective way to detect if a contract is + // under construction or not. + address self = address(this); + uint256 cs; + assembly { + cs := extcodesize(self) + } + return cs == 0; + } + + // Reserved storage space to allow for layout changes in the future. + uint256[50] private ______gap; +} + + +// Dependency file: contracts/truefi/common/UpgradeableOwnable.sol + +// pragma solidity 0.6.10; + +// import {Context} from "@openzeppelin/contracts/GSN/Context.sol"; + +// import {Initializable} from "contracts/truefi/common/Initializable.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +contract Ownable is Initializable, Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + function initialize() internal initializer { + address msgSender = _msgSender(); + _owner = msgSender; + emit OwnershipTransferred(address(0), msgSender); + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view returns (address) { + return _owner; + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(_owner == _msgSender(), "Ownable: caller is not the owner"); + _; + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby removing any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + emit OwnershipTransferred(_owner, address(0)); + _owner = address(0); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + emit OwnershipTransferred(_owner, newOwner); + _owner = newOwner; + } +} + + +// Dependency file: contracts/truefi/interface/IArbitraryDistributor.sol + +// pragma solidity 0.6.10; + +interface IArbitraryDistributor { + function amount() external returns (uint256); + + function remaining() external returns (uint256); + + function beneficiary() external returns (address); + + function distribute(uint256 _amount) external; + + function empty() external; +} + + +// Root file: contracts/truefi/distributors/RatingAgencyV2Distributor.sol + +pragma solidity 0.6.10; + +// import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +// import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; + +// import {Ownable} from "contracts/truefi/common/UpgradeableOwnable.sol"; +// import {IArbitraryDistributor} from "contracts/truefi/interface/IArbitraryDistributor.sol"; + +/** + * @title ArbitraryTrueDistributor + * @notice Distribute TRU to a smart contract + * @dev Allows for arbitrary claiming of TRU by a farm contract + * + * Contracts are registered to receive distributions. Once registered, + * a farm contract can claim TRU from the distributor. + * - Owner can withdraw funds in case distribution need to be re-allocated + */ +contract RatingAgencyV2Distributor is IArbitraryDistributor, Ownable { + using SafeMath for uint256; + + // ================ WARNING ================== + // ===== THIS CONTRACT IS INITIALIZABLE ====== + // === STORAGE VARIABLES ARE DECLARED BELOW == + // REMOVAL OR REORDER OF VARIABLES WILL RESULT + // ========= IN STORAGE CORRUPTION =========== + + IERC20 public trustToken; + address public override beneficiary; + uint256 public override amount; + uint256 public override remaining; + mapping(address => bool) public beneficiaries; + + // ======= STORAGE DECLARATION END ============ + + event Distributed(uint256 amount); + event BeneficiaryStatusChanged(address beneficiary, bool status); + + /** + * @dev Initialize distributor + * @param _beneficiary Address for distribution + * @param _trustToken TRU address + */ + function initialize(address _beneficiary, IERC20 _trustToken) public initializer { + Ownable.initialize(); + trustToken = _trustToken; + beneficiary = _beneficiary; + amount = 500000000000000; // 5M + remaining = 30000000000000000; // 300M + } + + /** + * @dev Only beneficiary can receive TRU + */ + modifier onlyBeneficiary { + // prettier-ignore + require(msg.sender == beneficiary || beneficiaries[msg.sender], + "ArbitraryDistributor: Only beneficiary can receive tokens"); + _; + } + + /** + * @dev Owner can set beneficiary status + * @param _beneficiary Contract which can claim TRU + * @param _status Boolean to set whether contract can claim TRU + */ + function setBeneficiaryStatus(address _beneficiary, bool _status) public onlyOwner { + beneficiaries[_beneficiary] = _status; + emit BeneficiaryStatusChanged(_beneficiary, _status); + } + + /** + * @dev Distribute arbitrary number of tokens + * @param _amount Amount of TRU to distribute + */ + function distribute(uint256 _amount) public override onlyBeneficiary { + remaining = remaining.sub(_amount); + require(trustToken.transfer(msg.sender, _amount)); + + emit Distributed(_amount); + } + + /** + * @dev Withdraw funds (for instance if owner decides to create a new distribution) and end distribution cycle + */ + function empty() public override onlyOwner { + remaining = 0; + require(trustToken.transfer(msg.sender, trustToken.balanceOf(address(this)))); + } +} diff --git a/flatten/StkTruToken.sol b/flatten/StkTruToken.sol index 3c0855431..6bda64da4 100644 --- a/flatten/StkTruToken.sol +++ b/flatten/StkTruToken.sol @@ -861,7 +861,7 @@ interface IVoteTokenWithERC20 is IVoteToken, IERC20 {} // Dependency file: contracts/governance/VoteToken.sol -// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol +// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/c5fcc34222693ad5f547b14ed01ce719b5f4b000/contracts/Governance/Comp.sol // Copyright 2020 Compound Labs, Inc. // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -871,12 +871,19 @@ interface IVoteTokenWithERC20 is IVoteToken, IERC20 {} // // Ctrl+f for OLD to see all the modifications. -// OLD: // pragma solidity ^0.5.16; // pragma solidity 0.6.10; // import {ERC20} from "contracts/trusttoken/common/ERC20.sol"; // import {IVoteToken} from "contracts/governance/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)"); @@ -888,6 +895,9 @@ abstract contract VoteToken is ERC20, IVoteToken { return _delegate(msg.sender, delegatee); } + /** + * @dev Delegate votes using signature + */ function delegateBySig( address delegatee, uint256 nonce, @@ -906,11 +916,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"); @@ -945,10 +966,15 @@ 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); - uint96 delegatorBalance = uint96(_balanceOf(delegator)); + uint96 delegatorBalance = safe96(_balanceOf(delegator), "StkTruToken: uint96 overflow"); delegates[delegator] = delegatee; emit DelegateChanged(delegator, currentDelegate, delegatee); @@ -966,7 +992,7 @@ abstract contract VoteToken is ERC20, IVoteToken { uint256 _value ) internal virtual override { super._transfer(_from, _to, _value); - _moveDelegates(delegates[_from], delegates[_to], uint96(_value)); + _moveDelegates(delegates[_from], delegates[_to], safe96(_value, "StkTruToken: uint96 overflow")); } function _mint(address account, uint256 amount) internal virtual override { @@ -979,6 +1005,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, @@ -1001,6 +1030,9 @@ abstract contract VoteToken is ERC20, IVoteToken { } } + /** + * @dev internal function to write a checkpoint for voting power + */ function _writeCheckpoint( address delegatee, uint32 nCheckpoints, @@ -1019,16 +1051,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, @@ -1039,6 +1080,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, @@ -1048,6 +1092,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 { @@ -1213,6 +1260,8 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { uint256 public undistributedTfusdRewards; uint32 public nextDistributionIndex; + mapping(address => bool) public whitelistedFeePayers; + // ======= STORAGE DECLARATION END ============ event Stake(address indexed staker, uint256 amount); @@ -1222,6 +1271,7 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { event Cooldown(address indexed who, uint256 endTime); event CooldownTimeChanged(uint256 newUnstakePeriodDuration); event UnstakePeriodDurationChanged(uint256 newUnstakePeriodDuration); + event FeePayerWhitelistingStatusChanged(address payer, bool status); /** * @dev Only Liquidator contract can perform TRU liquidations @@ -1231,6 +1281,14 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { _; } + /** + * @dev Only whitelisted payers can pay fees + */ + modifier onlyWhitelistedPayers() { + require(whitelistedFeePayers[msg.sender], "StkTruToken: Can be called only by whitelisted payers"); + _; + } + /** * Get TRU from distributor */ @@ -1244,6 +1302,10 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { _; } + /** + * Update all rewards when an account changes state + * @param account Account to update rewards for + */ modifier update(address account) { updateTotalRewards(tru); updateClaimableRewards(tru, account); @@ -1252,6 +1314,22 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { _; } + /** + * Update rewards for a specific token when an account changes state + * @param account Account to update rewards for + * @param token Token to update rewards for + */ + modifier updateRewards(address account, IERC20 token) { + if (token == tru) { + updateTotalRewards(tru); + updateClaimableRewards(tru, account); + } else if (token == tfusd) { + updateTotalRewards(tfusd); + updateClaimableRewards(tfusd, account); + } + _; + } + /** * @dev Initialize contract and set default values * @param _tru TRU token @@ -1278,6 +1356,17 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { initalized = true; } + /** + * @dev Owner can use this function to add new addresses to payers whitelist + * Only whitelisted payers can call payFee method + * @param payer Address that is being added to or removed from whitelist + * @param status New whitelisting status + */ + function setPayerWhitelistingStatus(address payer, bool status) external onlyOwner { + whitelistedFeePayers[payer] = status; + emit FeePayerWhitelistingStatusChanged(payer, status); + } + /** * @dev Owner can use this function to set cooldown time * Cooldown time defines how long a staker waits to unstake TRU @@ -1313,8 +1402,14 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { function stake(uint256 amount) external distribute update(msg.sender) { require(amount > 0, "StkTruToken: Cannot stake 0"); - if (cooldowns[msg.sender] != 0 && cooldowns[msg.sender].add(cooldownTime) > block.timestamp) { + if (cooldowns[msg.sender] != 0 && cooldowns[msg.sender].add(cooldownTime).add(unstakePeriodDuration) > block.timestamp) { cooldowns[msg.sender] = block.timestamp; + + emit Cooldown(msg.sender, block.timestamp.add(cooldownTime)); + } + + if (delegates[msg.sender] == address(0)) { + delegates[msg.sender] = msg.sender; } uint256 amountToMint = stakeSupply == 0 ? amount : amount.mul(totalSupply).div(stakeSupply); @@ -1389,7 +1484,7 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { * @dev Give tfUSD as origination fee to stake.this * 50% are given immediately and 50% after `endTime` passes */ - function payFee(uint256 amount, uint256 endTime) external { + function payFee(uint256 amount, uint256 endTime) external onlyWhitelistedPayers { require(endTime < type(uint64).max, "StkTruToken: time overflow"); require(amount < type(uint96).max, "StkTruToken: amount overflow"); @@ -1409,6 +1504,16 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { _claim(tfusd); } + /** + * @dev Claim rewards for specific token + * Allows account to claim specific token to save gas + * @param token Token to claim rewards for + */ + function claimRewards(IERC20 token) external distribute updateRewards(msg.sender, token) { + require(token == tfusd || token == tru, "Token not supported for rewards"); + _claim(token); + } + /** * @dev View to estimate the claimable reward for an account * @param account Account to get claimable reward for @@ -1509,7 +1614,10 @@ contract StkTruToken is VoteToken, ClaimableContract, ReentrancyGuard { if (token == tru) { return token.balanceOf(address(this)).sub(stakeSupply); } - return token.balanceOf(address(this)).sub(undistributedTfusdRewards); + if (token == tfusd) { + return token.balanceOf(address(this)).sub(undistributedTfusdRewards); + } + return 0; } /** @@ -1550,6 +1658,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) { @@ -1563,6 +1676,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) { @@ -1571,6 +1688,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/flatten/TimeLockRegistry.sol b/flatten/TimeLockRegistry.sol index 20a090e0a..017de5beb 100644 --- a/flatten/TimeLockRegistry.sol +++ b/flatten/TimeLockRegistry.sol @@ -864,7 +864,7 @@ interface IVoteTokenWithERC20 is IVoteToken, IERC20 {} // Dependency file: contracts/governance/VoteToken.sol -// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol +// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/c5fcc34222693ad5f547b14ed01ce719b5f4b000/contracts/Governance/Comp.sol // Copyright 2020 Compound Labs, Inc. // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -874,12 +874,19 @@ interface IVoteTokenWithERC20 is IVoteToken, IERC20 {} // // Ctrl+f for OLD to see all the modifications. -// OLD: // pragma solidity ^0.5.16; // pragma solidity 0.6.10; // import {ERC20} from "contracts/trusttoken/common/ERC20.sol"; // import {IVoteToken} from "contracts/governance/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)"); @@ -891,6 +898,9 @@ abstract contract VoteToken is ERC20, IVoteToken { return _delegate(msg.sender, delegatee); } + /** + * @dev Delegate votes using signature + */ function delegateBySig( address delegatee, uint256 nonce, @@ -909,11 +919,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"); @@ -948,10 +969,15 @@ 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); - uint96 delegatorBalance = uint96(_balanceOf(delegator)); + uint96 delegatorBalance = safe96(_balanceOf(delegator), "StkTruToken: uint96 overflow"); delegates[delegator] = delegatee; emit DelegateChanged(delegator, currentDelegate, delegatee); @@ -969,7 +995,7 @@ abstract contract VoteToken is ERC20, IVoteToken { uint256 _value ) internal virtual override { super._transfer(_from, _to, _value); - _moveDelegates(delegates[_from], delegates[_to], uint96(_value)); + _moveDelegates(delegates[_from], delegates[_to], safe96(_value, "StkTruToken: uint96 overflow")); } function _mint(address account, uint256 amount) internal virtual override { @@ -982,6 +1008,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, @@ -1004,6 +1033,9 @@ abstract contract VoteToken is ERC20, IVoteToken { } } + /** + * @dev internal function to write a checkpoint for voting power + */ function _writeCheckpoint( address delegatee, uint32 nCheckpoints, @@ -1022,16 +1054,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, @@ -1042,6 +1083,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, @@ -1051,6 +1095,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/flatten/TimeLockedToken.sol b/flatten/TimeLockedToken.sol index 0f396de3a..5e573bde3 100644 --- a/flatten/TimeLockedToken.sol +++ b/flatten/TimeLockedToken.sol @@ -796,7 +796,7 @@ interface IVoteTokenWithERC20 is IVoteToken, IERC20 {} // Dependency file: contracts/governance/VoteToken.sol -// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol +// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/c5fcc34222693ad5f547b14ed01ce719b5f4b000/contracts/Governance/Comp.sol // Copyright 2020 Compound Labs, Inc. // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -806,12 +806,19 @@ interface IVoteTokenWithERC20 is IVoteToken, IERC20 {} // // Ctrl+f for OLD to see all the modifications. -// OLD: // pragma solidity ^0.5.16; // pragma solidity 0.6.10; // import {ERC20} from "contracts/trusttoken/common/ERC20.sol"; // import {IVoteToken} from "contracts/governance/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)"); @@ -823,6 +830,9 @@ abstract contract VoteToken is ERC20, IVoteToken { return _delegate(msg.sender, delegatee); } + /** + * @dev Delegate votes using signature + */ function delegateBySig( address delegatee, uint256 nonce, @@ -841,11 +851,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"); @@ -880,10 +901,15 @@ 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); - uint96 delegatorBalance = uint96(_balanceOf(delegator)); + uint96 delegatorBalance = safe96(_balanceOf(delegator), "StkTruToken: uint96 overflow"); delegates[delegator] = delegatee; emit DelegateChanged(delegator, currentDelegate, delegatee); @@ -901,7 +927,7 @@ abstract contract VoteToken is ERC20, IVoteToken { uint256 _value ) internal virtual override { super._transfer(_from, _to, _value); - _moveDelegates(delegates[_from], delegates[_to], uint96(_value)); + _moveDelegates(delegates[_from], delegates[_to], safe96(_value, "StkTruToken: uint96 overflow")); } function _mint(address account, uint256 amount) internal virtual override { @@ -914,6 +940,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, @@ -936,6 +965,9 @@ abstract contract VoteToken is ERC20, IVoteToken { } } + /** + * @dev internal function to write a checkpoint for voting power + */ function _writeCheckpoint( address delegatee, uint32 nCheckpoints, @@ -954,16 +986,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, @@ -974,6 +1015,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, @@ -983,6 +1027,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/flatten/Timelock.sol b/flatten/Timelock.sol index 76e6c3ef1..3e8e9bf2e 100644 --- a/flatten/Timelock.sol +++ b/flatten/Timelock.sol @@ -259,7 +259,7 @@ contract ClaimableContract { // Root file: contracts/governance/Timelock.sol -// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol +// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/c5fcc34222693ad5f547b14ed01ce719b5f4b000/contracts/Timelock.sol // Copyright 2020 Compound Labs, Inc. // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -422,7 +422,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/flatten/TruPriceChainlinkOracle.sol b/flatten/TruPriceChainlinkOracle.sol new file mode 100644 index 000000000..e7addca3d --- /dev/null +++ b/flatten/TruPriceChainlinkOracle.sol @@ -0,0 +1,252 @@ +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +// Dependency file: @openzeppelin/contracts/math/SafeMath.sol + +// SPDX-License-Identifier: MIT + +// pragma solidity ^0.6.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations with added overflow + * checks. + * + * Arithmetic operations in Solidity wrap on overflow. This can easily result + * in bugs, because programmers usually assume that an overflow raises an + * error, which is the standard behavior in high level programming languages. + * `SafeMath` restores this intuition by reverting the transaction when an + * operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + + return c; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + return sub(a, b, "SafeMath: subtraction overflow"); + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b <= a, errorMessage); + uint256 c = a - b; + + return c; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) { + return 0; + } + + uint256 c = a * b; + require(c / a == b, "SafeMath: multiplication overflow"); + + return c; + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return div(a, b, "SafeMath: division by zero"); + } + + /** + * @dev Returns the integer division of two unsigned integers. Reverts with custom message on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b > 0, errorMessage); + uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + + return c; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + return mod(a, b, "SafeMath: modulo by zero"); + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * Reverts with custom message when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + require(b != 0, errorMessage); + return a % b; + } +} + + +// Dependency file: contracts/truefi/interface/ITruPriceOracle.sol + +// pragma solidity 0.6.10; + +interface ITruPriceOracle { + function usdToTru(uint256 amount) external view returns (uint256); + + function truToUsd(uint256 amount) external view returns (uint256); +} + + +// Root file: contracts/truefi/TruPriceChainlinkOracle.sol + +pragma solidity 0.6.10; + +// import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol"; +// import {ITruPriceOracle} from "contracts/truefi/interface/ITruPriceOracle.sol"; + +interface IChainLink { + function latestAnswer() external view returns (int256); +} + +contract TruPriceChainLinkOracle is ITruPriceOracle { + using SafeMath for uint256; + + IChainLink public chainlinkOracle; + + /** + * @param _chainlinkOracle ChainLink Oracle address + */ + constructor(IChainLink _chainlinkOracle) public { + chainlinkOracle = _chainlinkOracle; + } + + /** + * @dev converts from USD with 18 decimals to TRU with 8 decimals + * Divide by 100 since Chainlink returns 10 decimals and TRU is 8 decimals + * @param amount Amount in USD + * @return TRU value of USD input + */ + function usdToTru(uint256 amount) external override view returns (uint256) { + return amount.div(safeUint(chainlinkOracle.latestAnswer())).div(100); + } + + /** + * @dev converts from TRU with 8 decimals to USD with 18 decimals + * Multiply by 100 since Chainlink returns 10 decimals and TRU is 8 decimals + * @param amount Amount in TRU + * @return USD value of TRU input + */ + function truToUsd(uint256 amount) external override view returns (uint256) { + return amount.mul(safeUint(chainlinkOracle.latestAnswer())).mul(100); + } + + /** + * @dev convert int256 to uint256 + * @param value to convert to uint + */ + function safeUint(int256 value) internal pure returns (uint256) { + require(value >= 0, "TruPriceChainLinkOracle: uint underflow"); + return uint256(value); + } +} diff --git a/flatten/TruPriceUniswapOracle.sol b/flatten/TruPriceUniswapOracle.sol index ad9cf1811..75d87d6d4 100644 --- a/flatten/TruPriceUniswapOracle.sol +++ b/flatten/TruPriceUniswapOracle.sol @@ -23,6 +23,292 @@ ............... */ +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + +// https://github.com/trusttoken/smart-contracts +/* + .'''''''''''.. ..''''''''''''''''.. ..'''''''''''''''.. + .;;;;;;;;;;;'. .';;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;,. + .;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. .;;;;;;;;;;;;;;;;;;;;,. + ';;;;;;;;'. .';;;;;;;;;;;;;;;;;;;;;;,. .';;;;;;;;;;;;;;;;;;;;;,. + ';;;;;,.. .';;;;;;;;;;;;;;;;;;;;;;;,..';;;;;;;;;;;;;;;;;;;;;;,. + ...... .';;;;;;;;;;;;;,'''''''''''.,;;;;;;;;;;;;;,'''''''''.. + .,;;;;;;;;;;;;;. .,;;;;;;;;;;;;;. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;,. + .,;;;;;;;;;;;;,. .;;;;;;;;;;;;;,. ..... + .;;;;;;;;;;;;;'. ..';;;;;;;;;;;;;'. .',;;;;,'. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .';;;;;;;;;;. + .';;;;;;;;;;;;;'. .';;;;;;;;;;;;;;'. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;;'...........,;;;;;;;;;;;;;;. .;;;;;;;;;;;,. + .,;;;;;;;;;;;;,..,;;;;;;;;;;;;;;;;;;;;;;;,. ..;;;;;;;;;,. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;;,. .',;;;,,.. + .,;;;;;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;;,. .... + ..',;;;;;;;;,. .,;;;;;;;;;;;;;;;;;;;;,. + ..',;;;;'. .,;;;;;;;;;;;;;;;;;;;'. + ...'.. .';;;;;;;;;;;;;;,,,'. + ............... +*/ + // https://github.com/trusttoken/smart-contracts // Dependency file: @openzeppelin/contracts/math/SafeMath.sol diff --git a/flatten/TrueFiPool.sol b/flatten/TrueFiPool.sol index 1b51c03eb..be38c30e9 100644 --- a/flatten/TrueFiPool.sol +++ b/flatten/TrueFiPool.sol @@ -899,6 +899,11 @@ contract ERC20 is Initializable, Context, IERC20 { address to, uint256 amount ) internal virtual {} + + function updateNameAndSymbol(string memory __name, string memory __symbol) internal { + _name = __name; + _symbol = __symbol; + } } @@ -1210,6 +1215,17 @@ library ABDKMath64x64 { } +// Dependency file: contracts/truefi/interface/ITruPriceOracle.sol + +// pragma solidity 0.6.10; + +interface ITruPriceOracle { + function usdToTru(uint256 amount) external view returns (uint256); + + function truToUsd(uint256 amount) external view returns (uint256); +} + + // Root file: contracts/truefi/TrueFiPool.sol pragma solidity 0.6.10; @@ -1225,6 +1241,7 @@ pragma solidity 0.6.10; // import {ITrueLender} from "contracts/truefi/interface/ITrueLender.sol"; // import {IUniswapRouter} from "contracts/truefi/interface/IUniswapRouter.sol"; // import {ABDKMath64x64} from "contracts/truefi/Log.sol"; +// import {ITruPriceOracle} from "contracts/truefi/interface/ITruPriceOracle.sol"; /** * @title TrueFi Pool @@ -1270,6 +1287,16 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { uint256 private yTokenValueCache; uint256 private loansValueCache; + // TRU price oracle + ITruPriceOracle public _oracle; + + // fund manager can call functions to help manage pool funds + // fund manager can be set to 0 or governance + address public fundsManager; + + // allow pausing of deposits + bool public isJoiningPaused; + // ======= STORAGE DECLARATION END ============ // curve.fi data @@ -1282,6 +1309,18 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { */ event StakeTokenChanged(IERC20 token); + /** + * @dev Emitted oracle was changed + * @param newOracle New oracle address + */ + event OracleChanged(ITruPriceOracle newOracle); + + /** + * @dev Emitted when funds manager is changed + * @param newManager New manager address + */ + event FundsManagerChanged(address newManager); + /** * @dev Emitted when fee is changed * @param newFee New fee @@ -1337,6 +1376,12 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { */ event Collected(address indexed beneficiary, uint256 amount); + /** + * @dev Emitted when joining is paused or unpaused + * @param isJoiningPaused New pausing status + */ + event JoiningPauseStatusChanged(bool isJoiningPaused); + /** * @dev Initialize pool * @param __curvePool curve pool address @@ -1351,7 +1396,8 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { IERC20 __currencyToken, ITrueLender __lender, IUniswapRouter __uniRouter, - IERC20 __stakeToken + IERC20 __stakeToken, + ITruPriceOracle __oracle ) public initializer { ERC20.__ERC20_initialize("TrueFi LP", "TFI-LP"); Ownable.initialize(); @@ -1363,6 +1409,7 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { _minter = _curveGauge.minter(); _uniRouter = __uniRouter; _stakeToken = __stakeToken; + _oracle = __oracle; joiningFee = 25; } @@ -1375,6 +1422,22 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { _; } + /** + * @dev pool can only be joined when it's unpaused + */ + modifier joiningNotPaused() { + require(!isJoiningPaused, "TrueFiPool: Joining the pool is paused"); + _; + } + + /** + * @dev only lender can perform borrowing or repaying + */ + modifier onlyOwnerOrManager() { + require(msg.sender == owner() || msg.sender == fundsManager, "TrueFiPool: Caller is neither owner nor funds manager"); + _; + } + /** * Sync values to avoid making expensive calls multiple times * Will set inSync to true, allowing getter functions to return cached values @@ -1417,8 +1480,35 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { emit StakeTokenChanged(token); } + /** + * @dev set funds manager address + */ + function setFundsManager(address newFundsManager) public onlyOwner { + fundsManager = newFundsManager; + emit FundsManagerChanged(newFundsManager); + } + + /** + * @dev set oracle token address + * @param newOracle new oracle address + */ + function setOracle(ITruPriceOracle newOracle) public onlyOwner { + _oracle = newOracle; + emit OracleChanged(newOracle); + } + + /** + * @dev Allow pausing of deposits in case of emergency + * @param status New deposit status + */ + function changeJoiningPauseStatus(bool status) external onlyOwnerOrManager { + isJoiningPaused = status; + emit JoiningPauseStatusChanged(status); + } + /** * @dev Get total balance of stake tokens + * @return Balance of stake tokens in this contract */ function stakeTokenBalance() public view returns (uint256) { return _stakeToken.balanceOf(address(this)); @@ -1426,6 +1516,7 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { /** * @dev Get total balance of curve.fi pool tokens + * @return Balance of y pool tokens in this contract */ function yTokenBalance() public view returns (uint256) { return _curvePool.token().balanceOf(address(this)).add(_curveGauge.balanceOf(address(this))); @@ -1443,8 +1534,21 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { return yTokenBalance().mul(_curvePool.curve().get_virtual_price()).div(1 ether); } + /** + * @dev Price of TRU in USD + * @return Oracle price of TRU in USD + */ + function truValue() public view returns (uint256) { + uint256 balance = stakeTokenBalance(); + if (balance == 0) { + return 0; + } + return _oracle.truToUsd(balance); + } + /** * @dev Virtual value of liquid assets in the pool + * @return Virtual liquid value of pool assets */ function liquidValue() public view returns (uint256) { return currencyBalance().add(yTokenValue()); @@ -1453,9 +1557,10 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { /** * @dev Calculate pool value in TUSD * "virtual price" of entire pool - LoanTokens, TUSD, curve y pool tokens - * @return pool value in TUSD + * @return pool value in USD */ function poolValue() public view returns (uint256) { + // this assumes defaulted loans are worth their full value return liquidValue().add(loansValue()); } @@ -1507,7 +1612,7 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { * @dev Join the pool by depositing currency tokens * @param amount amount of currency token to deposit */ - function join(uint256 amount) external override { + function join(uint256 amount) external override joiningNotPaused { uint256 fee = amount.mul(joiningFee).div(10000); uint256 mintedAmount = mint(amount.sub(fee)); claimableFees = claimableFees.add(fee); @@ -1569,7 +1674,7 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { /** * @dev Exit pool only with liquid tokens * This function will withdraw TUSD but with a small penalty - * Uses the sync() modifer to reduce gas costs of using curve + * Uses the sync() modifier to reduce gas costs of using curve * @param amount amount of pool tokens to redeem for underlying tokens */ function liquidExit(uint256 amount) external nonReentrant sync { @@ -1637,7 +1742,7 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { * @param currencyAmount Amount of funds to deposit into curve * @param minMintAmount Minimum amount to mint */ - function flush(uint256 currencyAmount, uint256 minMintAmount) external onlyOwner { + function flush(uint256 currencyAmount, uint256 minMintAmount) external onlyOwnerOrManager { require(currencyAmount <= currencyBalance(), "TrueFiPool: Insufficient currency balance"); uint256[N_TOKENS] memory amounts = [0, 0, 0, currencyAmount]; @@ -1659,7 +1764,7 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { * @param yAmount amount of curve pool tokens * @param minCurrencyAmount minimum amount of tokens to withdraw */ - function pull(uint256 yAmount, uint256 minCurrencyAmount) external onlyOwner { + function pull(uint256 yAmount, uint256 minCurrencyAmount) external onlyOwnerOrManager { require(yAmount <= yTokenBalance(), "TrueFiPool: Insufficient Curve liquidity balance"); // unstake in gauge @@ -1714,7 +1819,7 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { /** * @dev Collect CRV tokens minted by staking at gauge */ - function collectCrv() external onlyOwner { + function collectCrv() external onlyOwnerOrManager { _minter.mint(address(_curveGauge)); } @@ -1733,16 +1838,36 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { uint256 amountIn, uint256 amountOutMin, address[] calldata path - ) public onlyOwner { + ) public onlyOwnerOrManager { _minter.token().approve(address(_uniRouter), amountIn); _uniRouter.swapExactTokensForTokens(amountIn, amountOutMin, path, address(this), block.timestamp + 1 hours); } + /** + * @dev Sell collected TRU on Uniswap + * - Selling TRU is managed by the contract owner + * - Calculations can be made off-chain and called based on market conditions + * - Need to pass path of exact pairs to go through while executing exchange + * For example, CRV -> WETH -> TUSD + * + * @param amountIn see https://uniswap.org/docs/v2/smart-contracts/router02/#swapexacttokensfortokens + * @param amountOutMin see https://uniswap.org/docs/v2/smart-contracts/router02/#swapexacttokensfortokens + * @param path see https://uniswap.org/docs/v2/smart-contracts/router02/#swapexacttokensfortokens + */ + function sellStakeToken( + uint256 amountIn, + uint256 amountOutMin, + address[] calldata path + ) public onlyOwnerOrManager { + _stakeToken.approve(address(_uniRouter), amountIn); + _uniRouter.swapExactTokensForTokens(amountIn, amountOutMin, path, address(this), block.timestamp + 1 hours); + } + /** * @dev Claim fees from the pool * @param beneficiary account to send funds to */ - function collectFees(address beneficiary) external onlyOwner { + function collectFees(address beneficiary) external onlyOwnerOrManager { uint256 amount = claimableFees; claimableFees = 0; @@ -1804,4 +1929,11 @@ contract TrueFiPool is ITrueFiPool, ERC20, ReentrancyGuard, Ownable { return mintedAmount; } + + /** + * @dev Update name and symbol of this contract + */ + function updateNameAndSymbol() public { + super.updateNameAndSymbol("TrueFi TrueUSD", "tfTUSD"); + } } diff --git a/flatten/TrueLender.sol b/flatten/TrueLender.sol index dd729d274..e82c5c918 100644 --- a/flatten/TrueLender.sol +++ b/flatten/TrueLender.sol @@ -773,6 +773,12 @@ contract TrueLender is ITrueLender, Ownable { */ event Reclaimed(address indexed loanToken, uint256 amount); + /** + * @dev Emitted when rating agency contract is changed + * @param newRatingAgency Address of new rating agency + */ + event RatingAgencyChanged(address newRatingAgency); + /** * @dev Modifier for only lending pool */ @@ -895,6 +901,15 @@ contract TrueLender is ITrueLender, Ownable { emit LoansLimitChanged(maxLoans); } + /** + * @dev Set new rating agency. Only owner can change parameters. + * @param newRatingAgency New rating agency. + */ + function setRatingAgency(ITrueRatingAgency newRatingAgency) external onlyOwner { + ratingAgency = newRatingAgency; + emit RatingAgencyChanged(address(newRatingAgency)); + } + /** * @dev Get currently funded loans * @return result Array of loans currently funded @@ -937,6 +952,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)); @@ -950,7 +967,7 @@ contract TrueLender is ITrueLender, Ownable { } uint256 helper = loan.amount().mul(loan.apy()).mul(passed).mul(_balance); - // assume month is 30 days + // assume year is 365 days uint256 interest = helper.div(365 days).div(10000).div(loan.debt()); return loan.amount().mul(_balance).div(loan.debt()).add(interest); @@ -971,7 +988,7 @@ contract TrueLender is ITrueLender, Ownable { /** * @dev For settled loans, redeem LoanTokens for underlying funds - * @param loanToken Loan to reclaim capital from + * @param loanToken Loan to reclaim capital from (must be previously funded) */ function reclaim(ILoanToken loanToken) external { require(loanToken.isLoanToken(), "TrueLender: Only LoanTokens can be used to reclaimed"); @@ -997,11 +1014,14 @@ contract TrueLender is ITrueLender, Ownable { if (_loans[index] == loanToken) { _loans[index] = _loans[_loans.length - 1]; _loans.pop(); - break; + + emit Reclaimed(address(loanToken), fundsReclaimed); + return; } } - - emit Reclaimed(address(loanToken), fundsReclaimed); + // 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/flatten/TrueRatingAgencyV2.sol b/flatten/TrueRatingAgencyV2.sol index adcec573b..8726e5276 100644 --- a/flatten/TrueRatingAgencyV2.sol +++ b/flatten/TrueRatingAgencyV2.sol @@ -626,11 +626,11 @@ interface ITrueFiPool is IERC20 { } -// Dependency file: contracts/truefi/interface/ITrueRatingAgency.sol +// Dependency file: contracts/truefi/interface/ITrueRatingAgencyV2.sol // pragma solidity 0.6.10; -interface ITrueRatingAgency { +interface ITrueRatingAgencyV2 { function getResults(address id) external view @@ -644,11 +644,9 @@ interface ITrueRatingAgency { function retract(address id) external; - function yes(address id, uint256 stake) external; + function yes(address id) external; - function no(address id, uint256 stake) external; - - function withdraw(address id, uint256 stake) external; + function no(address id) external; function claim(address id, address voter) external; } @@ -669,7 +667,7 @@ pragma solidity 0.6.10; // import {ILoanFactory} from "contracts/truefi/interface/ILoanFactory.sol"; // import {ILoanToken} from "contracts/truefi/interface/ILoanToken.sol"; // import {ITrueFiPool} from "contracts/truefi/interface/ITrueFiPool.sol"; -// import {ITrueRatingAgency} from "contracts/truefi/interface/ITrueRatingAgency.sol"; +// import {ITrueRatingAgencyV2} from "contracts/truefi/interface/ITrueRatingAgencyV2.sol"; /** * @title TrueRatingAgencyV2 @@ -677,15 +675,16 @@ pragma solidity 0.6.10; * * 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 vote YES or NO and stake TRU as collateral on their vote. + * 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 voters to earn and claim TRU - * incentive when the loan is passed + * Rating stkTRU in the prediction market allows raters to earn and claim TRU + * incentive when the loan is approved * * Voting Lifecycle: * - Borrowers can apply for loans at any time by deploying a LoanToken * - LoanTokens are registered with the prediction market contract - * - Once registered, stkTRU holders can vote at any time + * - Once registered, stkTRU holders can rate at any time * * States: * Void: Rated loan is invalid @@ -694,17 +693,19 @@ pragma solidity 0.6.10; * Running: Rated loan has been funded * Settled: Rated loan has been paid back in full * Defaulted: Rated loan has not been paid back in full + * Liquidated: Rated loan has defaulted and stakers have been liquidated */ -contract TrueRatingAgencyV2 is ITrueRatingAgency, Ownable { +contract TrueRatingAgencyV2 is ITrueRatingAgencyV2, Ownable { using SafeMath for uint256; - enum LoanStatus {Void, Pending, Retracted, Running, Settled, Defaulted} + enum LoanStatus {Void, Pending, Retracted, Running, Settled, Defaulted, Liquidated} struct Loan { address creator; uint256 timestamp; + uint256 blockNumber; mapping(bool => uint256) prediction; - mapping(address => mapping(bool => uint256)) votes; + mapping(address => mapping(bool => uint256)) ratings; mapping(address => uint256) claimed; uint256 reward; } @@ -731,22 +732,25 @@ contract TrueRatingAgencyV2 is ITrueRatingAgency, Ownable { */ uint256 public ratersRewardFactor; - // reward multiplier for voters + // reward multiplier for raters uint256 public rewardMultiplier; // are submissions paused? bool public submissionPauseStatus; + mapping(address => bool) public canChangeAllowance; + // ======= STORAGE DECLARATION END ============ + event CanChangeAllowanceChanged(address indexed who, bool status); event Allowed(address indexed who, bool status); event RatersRewardFactorChanged(uint256 ratersRewardFactor); event LoanSubmitted(address id); event LoanRetracted(address id); - event Voted(address loanToken, address voter, bool choice, uint256 stake); - event Withdrawn(address loanToken, address voter, uint256 stake, uint256 received, uint256 burned); + event Rated(address loanToken, address rater, bool choice, uint256 stake); + event Withdrawn(address loanToken, address rater, uint256 stake, uint256 received, uint256 burned); event RewardMultiplierChanged(uint256 newRewardMultiplier); - event Claimed(address loanToken, address voter, uint256 claimedReward); + event Claimed(address loanToken, address rater, uint256 claimedReward); event SubmissionPauseStatusChanged(bool status); /** @@ -790,7 +794,7 @@ contract TrueRatingAgencyV2 is ITrueRatingAgency, Ownable { } /** - * @dev Initalize Rating Agenct + * @dev Initialize Rating Agency * Distributor contract decides how much TRU is rewarded to stakers * @param _TRU TRU contract * @param _distributor Distributor contract @@ -833,36 +837,36 @@ contract TrueRatingAgencyV2 is ITrueRatingAgency, Ownable { } /** - * @dev Get number of NO votes for a specific account and loan + * @dev Get number of NO ratings for a specific account and loan * @param id Loan ID - * @param voter Voter account + * @param rater Rater account */ - function getNoVote(address id, address voter) public view returns (uint256) { - return loans[id].votes[voter][false]; + function getNoRate(address id, address rater) public view returns (uint256) { + return loans[id].ratings[rater][false]; } /** - * @dev Get number of YES votes for a specific account and loan + * @dev Get number of YES ratings for a specific account and loan * @param id Loan ID - * @param voter Voter account + * @param rater Rater account */ - function getYesVote(address id, address voter) public view returns (uint256) { - return loans[id].votes[voter][true]; + function getYesRate(address id, address rater) public view returns (uint256) { + return loans[id].ratings[rater][true]; } /** - * @dev Get total NO votes for a specific loan + * @dev Get total NO ratings for a specific loan * @param id Loan ID */ - function getTotalNoVotes(address id) public view returns (uint256) { + function getTotalNoRatings(address id) public view returns (uint256) { return loans[id].prediction[false]; } /** - * @dev Get total YES votes for a specific loan + * @dev Get total YES ratings for a specific loan * @param id Loan ID */ - function getTotalYesVotes(address id) public view returns (uint256) { + function getTotalYesRatings(address id) public view returns (uint256) { return loans[id].prediction[true]; } @@ -889,7 +893,15 @@ contract TrueRatingAgencyV2 is ITrueRatingAgency, Ownable { uint256 ) { - return (getVotingStart(id), getTotalNoVotes(id), getTotalYesVotes(id)); + return (getVotingStart(id), getTotalNoRatings(id), getTotalYesRatings(id)); + } + + /** + * @dev Allows addresses to whitelist borrowers + */ + function allowChangingAllowances(address who, bool status) external onlyOwner { + canChangeAllowance[who] = status; + emit CanChangeAllowanceChanged(who, status); } /** @@ -897,7 +909,8 @@ contract TrueRatingAgencyV2 is ITrueRatingAgency, Ownable { * @param who Account to whitelist * @param status Flag to whitelist accounts */ - function allow(address who, bool status) external onlyOwner { + function allow(address who, bool status) external { + require(canChangeAllowance[msg.sender], "TrueFiPool: Cannot change allowances"); allowedSubmitters[who] = status; emit Allowed(who, status); } @@ -920,7 +933,7 @@ contract TrueRatingAgencyV2 is ITrueRatingAgency, Ownable { require(!submissionPauseStatus, "TrueRatingAgencyV2: New submissions are paused"); require(ILoanToken(id).borrower() == msg.sender, "TrueRatingAgencyV2: Sender is not borrower"); require(factory.isLoanToken(id), "TrueRatingAgencyV2: Only LoanTokens created via LoanFactory are supported"); - loans[id] = Loan({creator: msg.sender, timestamp: block.timestamp, reward: 0}); + loans[id] = Loan({creator: msg.sender, timestamp: block.timestamp, blockNumber: block.number, reward: 0}); emit LoanSubmitted(id); } @@ -938,75 +951,58 @@ contract TrueRatingAgencyV2 is ITrueRatingAgency, Ownable { } /** - * @dev Vote on a loan by staking TRU + * @dev Rate on a loan by staking TRU * @param id Loan ID - * @param stake Amount of TRU to stake - * @param choice Voter choice. false = NO, true = YES + * @param choice Rater choice. false = NO, true = YES */ - function vote( - address id, - uint256 stake, - bool choice - ) internal { - require(loans[id].votes[msg.sender][!choice] == 0, "TrueRatingAgencyV2: Cannot vote both yes and no"); + function rate(address id, bool choice) internal { + uint256 stake = stkTRU.getPriorVotes(msg.sender, loans[id].blockNumber); + require(stake > 0, "TrueRatingAgencyV2: Cannot rate with empty balance"); + + resetCastRatings(id); loans[id].prediction[choice] = loans[id].prediction[choice].add(stake); - loans[id].votes[msg.sender][choice] = loans[id].votes[msg.sender][choice].add(stake); + loans[id].ratings[msg.sender][choice] = loans[id].ratings[msg.sender][choice].add(stake); - require(stkTRU.transferFrom(msg.sender, address(this), stake)); - emit Voted(id, msg.sender, choice, stake); + emit Rated(id, msg.sender, choice, stake); } - /** - * @dev Vote YES on a loan by staking TRU + /** + * @dev Internal function to help reset ratings * @param id Loan ID - * @param stake Amount of TRU to stake + * @param choice Boolean representing choice */ - function yes(address id, uint256 stake) external override onlyPendingLoans(id) { - vote(id, stake, true); + function _resetCastRatings(address id, bool choice) internal { + loans[id].prediction[choice] = loans[id].prediction[choice].sub(loans[id].ratings[msg.sender][choice]); + loans[id].ratings[msg.sender][choice] = 0; } /** - * @dev Vote NO on a loan by staking TRU - * @param id Loan ID - * @param stake Amount of TRU to stake + * @dev Cancel ratings of msg.sender + * @param id ID to cancel ratings for */ - function no(address id, uint256 stake) external override onlyPendingLoans(id) { - vote(id, stake, false); + function resetCastRatings(address id) public onlyPendingLoans(id) { + if (getYesRate(id, msg.sender) > 0) { + _resetCastRatings(id, true); + } else if (getNoRate(id, msg.sender) > 0) { + _resetCastRatings(id, false); + } } - // prettier-ignore /** - * @dev Withdraw stake on a loan and remove votes. + * @dev Rate YES on a loan by staking TRU * @param id Loan ID - * @param stake Amount of TRU to unstake */ - function withdraw(address id, uint256 stake) external override { - bool choice = loans[id].votes[msg.sender][true] > 0; - LoanStatus loanStatus = status(id); - - require(loans[id].votes[msg.sender][choice] >= stake, - "TrueRatingAgencyV2: Cannot withdraw more than was staked"); - - uint256 amountToTransfer = stake; - uint256 burned = 0; - - // if loan still pending, update total votes - if (loanStatus == LoanStatus.Pending) { - loans[id].prediction[choice] = loans[id].prediction[choice].sub(stake); - } - - // if loan status passed pending state claim TRU reward - if (loanStatus >= LoanStatus.Running) { - claim(id, msg.sender); - } - - // update account votes - loans[id].votes[msg.sender][choice] = loans[id].votes[msg.sender][choice].sub(stake); + function yes(address id) external override onlyPendingLoans(id) { + rate(id, true); + } - // transfer tokens to sender and emit event - require(stkTRU.transfer(msg.sender, amountToTransfer)); - emit Withdrawn(id, msg.sender, stake, amountToTransfer, burned); + /** + * @dev Rate NO on a loan by staking TRU + * @param id Loan ID + */ + function no(address id) external override onlyPendingLoans(id) { + rate(id, false); } /** @@ -1050,66 +1046,63 @@ contract TrueRatingAgencyV2 is ITrueRatingAgency, Ownable { } /** - * @dev Claim TRU rewards for voters + * @dev Claim TRU rewards for raters * - Only can claim TRU rewards for funded loans * - Claimed automatically when a user withdraws stake * * chi = (TRU remaining in distributor) / (Total TRU allocated for distribution) * interest = (loan APY * term * principal) * R = Total Reward = (interest * chi) - * R is distributed to voters based on their proportion of votes/total_votes + * R is distributed to raters based on their proportion of ratings/total_ratings * * Claimable reward = R x (current time / total time) * * (account TRU staked / total TRU staked) - (amount claimed) * * @param id Loan ID - * @param voter Voter account + * @param rater Rater account */ - function claim(address id, address voter) public override onlyFundedLoans(id) calculateTotalReward(id) { - uint256 claimableRewards = claimable(id, voter); + function claim(address id, address rater) external override onlyFundedLoans(id) calculateTotalReward(id) { + uint256 claimableRewards = claimable(id, rater); if (claimableRewards > 0) { // track amount of claimed tokens - loans[id].claimed[voter] = loans[id].claimed[voter].add(claimableRewards); + loans[id].claimed[rater] = loans[id].claimed[rater].add(claimableRewards); // transfer tokens - require(TRU.transfer(voter, claimableRewards)); - emit Claimed(id, voter, claimableRewards); + require(TRU.transfer(rater, claimableRewards)); + emit Claimed(id, rater, claimableRewards); } } /** - * @dev Get amount claimed for loan ID and voter address + * @dev Get amount claimed for loan ID and rater address * @param id Loan ID - * @param voter Voter address + * @param rater Rater address * @return Amount claimed for id and address */ - function claimed(address id, address voter) external view returns (uint256) { - return loans[id].claimed[voter]; + function claimed(address id, address rater) external view returns (uint256) { + return loans[id].claimed[rater]; } /** - * @dev Get amount claimable for loan ID and voter address + * @dev Get amount claimable for loan ID and rater address * @param id Loan ID - * @param voter Voter address + * @param rater Rater address * @return Amount claimable for id and address */ - function claimable(address id, address voter) public view returns (uint256) { + function claimable(address id, address rater) public view returns (uint256) { if (status(id) < LoanStatus.Running) { return 0; } // calculate how many tokens user can claim - // claimable = stakedByVoter / totalStaked - uint256 stakedByVoter = loans[id].votes[voter][false].add(loans[id].votes[voter][true]); + // claimable = stakedByRater / totalStaked + uint256 stakedByRater = loans[id].ratings[rater][false].add(loans[id].ratings[rater][true]); uint256 totalStaked = loans[id].prediction[false].add(loans[id].prediction[true]); // calculate claimable rewards at current time - uint256 totalClaimable = loans[id].reward.mul(stakedByVoter).div(totalStaked); - if (totalClaimable < loans[id].claimed[voter]) { - // This happens only in one case: voter withdrew part of stake after loan has ended and claimed all possible rewards - return 0; - } - return totalClaimable.sub(loans[id].claimed[voter]); + uint256 totalClaimable = loans[id].reward.mul(stakedByRater).div(totalStaked); + + return totalClaimable.sub(loans[id].claimed[rater]); } /** @@ -1143,6 +1136,10 @@ contract TrueRatingAgencyV2 is ITrueRatingAgency, Ownable { if (loanInternalStatus == ILoanToken.Status.Defaulted) { return LoanStatus.Defaulted; } + // Liquidated is same as defaulted and stakers have been liquidated + if (loanInternalStatus == ILoanToken.Status.Liquidated) { + return LoanStatus.Liquidated; + } // otherwise return Pending return LoanStatus.Pending; } diff --git a/flatten/TrustToken.sol b/flatten/TrustToken.sol index 7723a2a82..fc93c3f12 100644 --- a/flatten/TrustToken.sol +++ b/flatten/TrustToken.sol @@ -796,7 +796,7 @@ interface IVoteTokenWithERC20 is IVoteToken, IERC20 {} // Dependency file: contracts/governance/VoteToken.sol -// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol +// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/c5fcc34222693ad5f547b14ed01ce719b5f4b000/contracts/Governance/Comp.sol // Copyright 2020 Compound Labs, Inc. // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -806,12 +806,19 @@ interface IVoteTokenWithERC20 is IVoteToken, IERC20 {} // // Ctrl+f for OLD to see all the modifications. -// OLD: // pragma solidity ^0.5.16; // pragma solidity 0.6.10; // import {ERC20} from "contracts/trusttoken/common/ERC20.sol"; // import {IVoteToken} from "contracts/governance/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)"); @@ -823,6 +830,9 @@ abstract contract VoteToken is ERC20, IVoteToken { return _delegate(msg.sender, delegatee); } + /** + * @dev Delegate votes using signature + */ function delegateBySig( address delegatee, uint256 nonce, @@ -841,11 +851,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"); @@ -880,10 +901,15 @@ 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); - uint96 delegatorBalance = uint96(_balanceOf(delegator)); + uint96 delegatorBalance = safe96(_balanceOf(delegator), "StkTruToken: uint96 overflow"); delegates[delegator] = delegatee; emit DelegateChanged(delegator, currentDelegate, delegatee); @@ -901,7 +927,7 @@ abstract contract VoteToken is ERC20, IVoteToken { uint256 _value ) internal virtual override { super._transfer(_from, _to, _value); - _moveDelegates(delegates[_from], delegates[_to], uint96(_value)); + _moveDelegates(delegates[_from], delegates[_to], safe96(_value, "StkTruToken: uint96 overflow")); } function _mint(address account, uint256 amount) internal virtual override { @@ -914,6 +940,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, @@ -936,6 +965,9 @@ abstract contract VoteToken is ERC20, IVoteToken { } } + /** + * @dev internal function to write a checkpoint for voting power + */ function _writeCheckpoint( address delegatee, uint32 nCheckpoints, @@ -954,16 +986,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, @@ -974,6 +1015,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, @@ -983,6 +1027,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/flatten/UpgradeableERC20.sol b/flatten/UpgradeableERC20.sol index ece9af8bc..db0b25c7f 100644 --- a/flatten/UpgradeableERC20.sol +++ b/flatten/UpgradeableERC20.sol @@ -834,4 +834,9 @@ contract ERC20 is Initializable, Context, IERC20 { address to, uint256 amount ) internal virtual {} + + function updateNameAndSymbol(string memory __name, string memory __symbol) internal { + _name = __name; + _symbol = __symbol; + } } diff --git a/flatten/VoteToken.sol b/flatten/VoteToken.sol index 0b18ae0ab..9b77c62a1 100644 --- a/flatten/VoteToken.sol +++ b/flatten/VoteToken.sol @@ -796,7 +796,7 @@ interface IVoteTokenWithERC20 is IVoteToken, IERC20 {} // Root file: contracts/governance/VoteToken.sol -// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol +// AND COPIED FROM https://github.com/compound-finance/compound-protocol/blob/c5fcc34222693ad5f547b14ed01ce719b5f4b000/contracts/Governance/Comp.sol // Copyright 2020 Compound Labs, Inc. // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -806,12 +806,19 @@ interface IVoteTokenWithERC20 is IVoteToken, IERC20 {} // // Ctrl+f for OLD to see all the modifications. -// OLD: pragma solidity ^0.5.16; pragma solidity 0.6.10; // import {ERC20} from "contracts/trusttoken/common/ERC20.sol"; // import {IVoteToken} from "contracts/governance/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)"); @@ -823,6 +830,9 @@ abstract contract VoteToken is ERC20, IVoteToken { return _delegate(msg.sender, delegatee); } + /** + * @dev Delegate votes using signature + */ function delegateBySig( address delegatee, uint256 nonce, @@ -841,11 +851,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"); @@ -880,10 +901,15 @@ 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); - uint96 delegatorBalance = uint96(_balanceOf(delegator)); + uint96 delegatorBalance = safe96(_balanceOf(delegator), "StkTruToken: uint96 overflow"); delegates[delegator] = delegatee; emit DelegateChanged(delegator, currentDelegate, delegatee); @@ -901,7 +927,7 @@ abstract contract VoteToken is ERC20, IVoteToken { uint256 _value ) internal virtual override { super._transfer(_from, _to, _value); - _moveDelegates(delegates[_from], delegates[_to], uint96(_value)); + _moveDelegates(delegates[_from], delegates[_to], safe96(_value, "StkTruToken: uint96 overflow")); } function _mint(address account, uint256 amount) internal virtual override { @@ -914,6 +940,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, @@ -936,6 +965,9 @@ abstract contract VoteToken is ERC20, IVoteToken { } } + /** + * @dev internal function to write a checkpoint for voting power + */ function _writeCheckpoint( address delegatee, uint32 nCheckpoints, @@ -954,16 +986,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, @@ -974,6 +1015,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, @@ -983,6 +1027,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/scripts/deploy_truefi.ts b/scripts/deploy_truefi.ts index 10ba2897d..6fa3f2237 100644 --- a/scripts/deploy_truefi.ts +++ b/scripts/deploy_truefi.ts @@ -1,44 +1,125 @@ /* eslint-disable */ /** - * ts-node scripts/deploy_truefi.ts "{private_key}" "{network}" + * PRIVATE_KEY={private_key} ts-node scripts/deploy_truefi.ts "{network}" */ +import { ethers, providers } from 'ethers' -async function deployTrueFi () { - /* - const txnArgs = { gasLimit: 2_500_000, gasPrice: 100_000_000_000 } - const provider = new providers.InfuraProvider(process.argv[3], '81447a33c1cd4eb09efb1e8c388fb28e') - const wallet = new ethers.Wallet(process.argv[2], provider) +import { + OwnedUpgradeabilityProxyFactory, + RatingAgencyV2DistributorFactory, + LinearTrueDistributorFactory, + TrueRatingAgencyV2Factory, + StkTruTokenFactory, + GovernorAlphaFactory, + TimelockFactory, + LoanFactoryFactory, + LiquidatorFactory, + TruPriceChainLinkOracleFactory, + TrueRatingAgencyFactory, + TrueLenderFactory, + TrueFiPoolFactory, + TrustTokenFactory, +} from '../build' - const truAddress = await ask('TrustToken address: ') - console.log('Current block ', await provider.getBlockNumber()) - const startingBlock = Number.parseInt(await ask('Starting block: ')) +const txnArgs = { gasLimit: 1_500_000, gasPrice: 130_000_000_000 } +const contractArgs = { gasLimit: 5_500_000, gasPrice: txnArgs.gasPrice } - const slowDistributor = await (await new SlowTrueDistributorFactory(wallet).deploy(txnArgs)).deployed() - await (await slowDistributor.initialize(startingBlock, truAddress)).wait() +async function deployTruefi () { + const provider = new providers.InfuraProvider(process.argv[2], 'e33335b99d78415b82f8b9bc5fdc44c0') + const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider) + // await deployImplementations(wallet) + // await deployProxies(wallet) + // await deployProxiesWithImpl(wallet) + // await deployLoanFactory(wallet) + // await deployDistributor(wallet) + // await deployAddressBehindProxy(wallet, '', 'TruePriceOracle') +} + +async function deployImplementations (wallet) { + const trueRatingAgencyImpl = await (await new TrueRatingAgencyFactory(wallet).deploy(contractArgs)).deployed() + console.log(`TrueRatingAgency: ${trueRatingAgencyImpl.address}`) + + const trueLenderImpl = await (await new TrueLenderFactory(wallet).deploy(contractArgs)).deployed() + console.log(`TrueLender: ${trueLenderImpl.address}`) + + const trueFiPoolImpl = await (await new TrueFiPoolFactory(wallet).deploy(contractArgs)).deployed() + console.log(`TrueFiPool: ${trueFiPoolImpl.address}`) + + const trustTokenImpl = await (await new TrustTokenFactory(wallet).deploy(contractArgs)).deployed() + console.log(`TrustToken: ${trustTokenImpl.address}`) +} + +async function deployProxies(wallet) { + + const ratingAgencyV2DistributorImpl = await (await new RatingAgencyV2DistributorFactory(wallet).deploy(contractArgs)).deployed() + console.log(`RatingAgencyV2Distributor: ${ratingAgencyV2DistributorImpl.address}`) + + const linearTrueDistributorImpl = await (await new LinearTrueDistributorFactory(wallet).deploy(contractArgs)).deployed() + console.log(`LinearTrueDistributor: ${linearTrueDistributorImpl.address}`) + + const trueRatingAgencyV2Impl = await (await new TrueRatingAgencyV2Factory(wallet).deploy(contractArgs)).deployed() + console.log(`TrueRatingAgencyV2: ${trueRatingAgencyV2Impl.address}`) + + const stkTruTokenImpl = await (await new StkTruTokenFactory(wallet).deploy(contractArgs)).deployed() + console.log(`StkTruToken: ${stkTruTokenImpl.address}`) - const fastDistributor = await (await new FastTrueDistributorFactory(wallet).deploy(txnArgs)).deployed() - await (await fastDistributor.initialize(startingBlock, truAddress)).wait() + const governorAlphaImpl = await (await new GovernorAlphaFactory(wallet).deploy(contractArgs)).deployed() + console.log(`GovernorAlpha: ${governorAlphaImpl.address}`) - const blpAddress = await ask('Balancer BAL/TRU LP address: ') - const balancerFarm = await (await new TrueFarmFactory(wallet).deploy(txnArgs)).deployed() - await (await balancerFarm.initialize(blpAddress, fastDistributor.address, 'BAL/TRU Farm')).wait() - console.log('Balancer TrueFarm address: ', balancerFarm.address) + const timelockImpl = await (await new TimelockFactory(wallet).deploy(contractArgs)).deployed() + console.log(`Timelock: ${timelockImpl.address}`) - const ulpEthAddress = await ask('Uniswap ETH/TRU LP address: ') - const uniswapEthFarm = await (await new TrueFarmFactory(wallet).deploy(txnArgs)).deployed() - await (await uniswapEthFarm.initialize(ulpEthAddress, fastDistributor.address, 'ETH/TRU Farm')).wait() - console.log('Uniswap ETH/TRU TrueFarm address: ', uniswapEthFarm.address) + const liquidatorImpl = await (await new LiquidatorFactory(wallet).deploy(contractArgs)).deployed() + console.log(`Liquidator: ${liquidatorImpl.address}`) - const ulpTusdAddress2 = await ask('Uniswap TUSD/TrueFiLP address: ') - const uniswapTusdFarm = await (await new TrueFarmFactory(wallet).deploy(txnArgs)).deployed() - await (await uniswapTusdFarm.initialize(ulpTusdAddress2, slowDistributor.address, 'TUSD/TrueFiLP Farm')).wait() - console.log('Uniswap TUSD/TrueFiLP TrueFarm address: ', uniswapTusdFarm.address) + const truPriceChainLinkOracle = await (await new TruPriceChainLinkOracleFactory(wallet).deploy('0xa7becdd46648110112c85dd489a70f1119c81698', contractArgs)).deployed() + console.log(`TruPriceChainLinkOracle: ${truPriceChainLinkOracle.address}`) + + await deployContractBehindProxy(wallet, ratingAgencyV2DistributorImpl, 'ratingAgencyV2Distributor') + await deployContractBehindProxy(wallet, linearTrueDistributorImpl, 'linearTrueDistributor') + await deployContractBehindProxy(wallet, trueRatingAgencyV2Impl, 'trueRatingAgencyV2') + await deployContractBehindProxy(wallet, stkTruTokenImpl, 'stkTruToken') + await deployContractBehindProxy(wallet, governorAlphaImpl, 'governorAlpha') + await deployContractBehindProxy(wallet, timelockImpl, 'timelock') + await deployContractBehindProxy(wallet, liquidatorImpl, 'liquidator') +} + +async function deployContractBehindProxy(wallet, contract, name) { + const proxy = await (await new OwnedUpgradeabilityProxyFactory(wallet).deploy(txnArgs)).deployed() + await proxy.upgradeTo(contract.address, txnArgs) + console.log(`${name} proxy at: ${proxy.address}`) +} + + +async function deployProxiesWithImpl(wallet) { + const contracts = [ + { name: 'RatingAgencyV2Distributor', address: '0xF931f6c549F7FbBD41192eE13D6f2278493dD46b' }, + { name: 'LinearTrueDistributor', address: '0x1Bd6423320f8450A4bcD64E16F9cc228f589d1B9' }, + { name: 'TrueRatingAgencyV2', address: '0x353488058bA40b280B73C06FEAdA42CA4d61f7Fc' }, + { name: 'StkTruToken', address: '0xA367647cfc0525CBbdEe6EA036617E0884e3128b' }, + { name: 'GovernorAlpha', address: '0x8BEF17e7E0F339ddCE09842be757786e2Fe35D32' }, + { name: 'Timelock', address: '0x7762BC14f475fd8Ba8F994DD17bee91D2D280Db7' }, + { name: 'Liquidator', address: '0xA5C6B8930373972c5b67cd8bF4F3DaDBDA82F772' } + ] + for (let i = 0; i < contracts.length; i++) { + await deployAddressBehindProxy(wallet, contracts[i].address, contracts[i].name) + } +} + +async function deployAddressBehindProxy(wallet, address, name) { + const proxy = await (await new OwnedUpgradeabilityProxyFactory(wallet).deploy(txnArgs)).deployed() + await proxy.upgradeTo(address, txnArgs) + console.log(`${name} proxy at: ${proxy.address}`) +} + +async function deployLoanFactory(wallet) { + const loanFactoryImpl = await (await new LoanFactoryFactory(wallet).deploy(contractArgs)).deployed() + console.log(`LoanFactory: ${loanFactoryImpl.address}`) +} - await (await fastDistributor.transfer(wallet.address, balancerFarm.address, 5000000, txnArgs)).wait() - await (await fastDistributor.transfer(wallet.address, uniswapEthFarm.address, 5000000, txnArgs)).wait() - await (await slowDistributor.transfer(wallet.address, uniswapTusdFarm.address, 10000000, txnArgs)).wait() - console.log('TrueFi deployment completed') - */ +async function deployDistributor(wallet) { + const ratingAgencyDistributorImpl = await (await new RatingAgencyV2DistributorFactory(wallet).deploy(contractArgs)).deployed() + console.log(`RatingAgencyV2Distributor: ${ratingAgencyDistributorImpl.address}`) } -deployTrueFi().catch(console.error) +deployTruefi().catch(console.error) diff --git a/test/governance/StkTruToken.test.ts b/test/governance/StkTruToken.test.ts index e8ce5c511..d8b4e372d 100644 --- a/test/governance/StkTruToken.test.ts +++ b/test/governance/StkTruToken.test.ts @@ -250,14 +250,14 @@ describe('StkTruToken', () => { const balanceBefore = await tru.balanceOf(owner.address) expectScaledCloseTo(await stkToken.claimable(owner.address, tru.address), parseTRU(1000)) await stkToken.claimRewards(tru.address, { gasLimit: 3000000 }) - expect(await tru.balanceOf(owner.address)).to.equal(balanceBefore.add(parseTRU(1000))) + expectScaledCloseTo(await tru.balanceOf(owner.address), balanceBefore.add(parseTRU(1000))) }) it('claim only tfUSD', async () => { const balanceBefore = await tfusd.balanceOf(owner.address) expect(await stkToken.claimable(owner.address, tfusd.address)).to.equal(parseEth(1)) await stkToken.claimRewards(tfusd.address, { gasLimit: 3000000 }) - expect(await tfusd.balanceOf(owner.address)).to.equal(balanceBefore.add(parseEth(1))) + expectScaledCloseTo(await tfusd.balanceOf(owner.address), (balanceBefore.add(parseEth(1)))) }) it('claimable returns 0 for non-rewards tokens', async () => { diff --git a/test/truefi/distributors/ArbitraryDistributor.test.ts b/test/truefi/distributors/ArbitraryDistributor.test.ts index 965e45fd3..d1e80e7cd 100644 --- a/test/truefi/distributors/ArbitraryDistributor.test.ts +++ b/test/truefi/distributors/ArbitraryDistributor.test.ts @@ -55,6 +55,10 @@ describe('ArbitraryDistributor', () => { expect(await distributor.beneficiaries(otherWallet.address)).to.be.false }) + it('only owner can set beneficiary status', async () => { + await expect(distributor.connect(otherWallet).setBeneficiaryStatus(otherWallet.address, true)).to.be.reverted + }) + it('emits proper event', async () => { await expect(distributor.setBeneficiaryStatus(otherWallet.address, true)) .to.emit(distributor, 'BeneficiaryStatusChanged')