编译器
0.5.17+commit.d19bba13
文件 1 的 51:ATokenMock.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../libs/DecMath.sol";
contract ATokenMock is ERC20, ERC20Detailed {
using SafeMath for uint256;
using DecMath for uint256;
uint256 internal constant YEAR = 31556952;
ERC20 public dai;
uint256 public liquidityRate;
uint256 public normalizedIncome;
address[] public users;
mapping(address => bool) public isUser;
constructor(address _dai)
public
ERC20Detailed("aDAI", "aDAI", 18)
{
dai = ERC20(_dai);
liquidityRate = 10 ** 26;
normalizedIncome = 10 ** 27;
}
function redeem(uint256 _amount) external {
_burn(msg.sender, _amount);
dai.transfer(msg.sender, _amount);
}
function mint(address _user, uint256 _amount) external {
_mint(_user, _amount);
if (!isUser[_user]) {
users.push(_user);
isUser[_user] = true;
}
}
function mintInterest(uint256 _seconds) external {
uint256 interest;
address user;
for (uint256 i = 0; i < users.length; i++) {
user = users[i];
interest = balanceOf(user).mul(_seconds).mul(liquidityRate).div(YEAR.mul(10**27));
_mint(user, interest);
}
normalizedIncome = normalizedIncome.mul(_seconds).mul(liquidityRate).div(YEAR.mul(10**27)).add(normalizedIncome);
}
function setLiquidityRate(uint256 _liquidityRate) external {
liquidityRate = _liquidityRate;
}
}
文件 2 的 51:AaveMarket.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/ownership/Ownable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "../IMoneyMarket.sol";
import "./imports/IAToken.sol";
import "./imports/ILendingPool.sol";
import "./imports/ILendingPoolAddressesProvider.sol";
import "./imports/ILendingPoolCore.sol";
contract AaveMarket is IMoneyMarket, Ownable {
using SafeMath for uint256;
using SafeERC20 for ERC20;
using Address for address;
uint16 internal constant REFERRALCODE = 20;
ILendingPoolAddressesProvider public provider;
ERC20 public stablecoin;
constructor(address _provider, address _stablecoin) public {
require(
_provider != address(0) && _stablecoin != address(0),
"AaveMarket: An input address is 0"
);
require(
_provider.isContract() && _stablecoin.isContract(),
"AaveMarket: An input address is not a contract"
);
provider = ILendingPoolAddressesProvider(_provider);
stablecoin = ERC20(_stablecoin);
}
function deposit(uint256 amount) external onlyOwner {
require(amount > 0, "AaveMarket: amount is 0");
ILendingPool lendingPool = ILendingPool(provider.getLendingPool());
address lendingPoolCore = provider.getLendingPoolCore();
stablecoin.safeTransferFrom(msg.sender, address(this), amount);
stablecoin.safeIncreaseAllowance(lendingPoolCore, amount);
lendingPool.deposit(address(stablecoin), amount, REFERRALCODE);
}
function withdraw(uint256 amountInUnderlying)
external
onlyOwner
returns (uint256 actualAmountWithdrawn)
{
require(amountInUnderlying > 0, "AaveMarket: amountInUnderlying is 0");
ILendingPool lendingPool = ILendingPool(provider.getLendingPool());
(, , , , , , , , , , , address aTokenAddress, ) = lendingPool
.getReserveData(address(stablecoin));
IAToken aToken = IAToken(aTokenAddress);
aToken.redeem(amountInUnderlying);
stablecoin.safeTransfer(msg.sender, amountInUnderlying);
return amountInUnderlying;
}
function claimRewards() external {}
function totalValue() external returns (uint256) {
ILendingPool lendingPool = ILendingPool(provider.getLendingPool());
(, , , , , , , , , , , address aTokenAddress, ) = lendingPool
.getReserveData(address(stablecoin));
IAToken aToken = IAToken(aTokenAddress);
return aToken.balanceOf(address(this));
}
function incomeIndex() external returns (uint256) {
ILendingPoolCore lendingPoolCore = ILendingPoolCore(
provider.getLendingPoolCore()
);
return lendingPoolCore.getReserveNormalizedIncome(address(stablecoin));
}
function setRewards(address newValue) external {}
}
文件 3 的 51:Address.sol
pragma solidity ^0.5.5;
library Address {
function isContract(address account) internal view returns (bool) {
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
function toPayable(address account) internal pure returns (address payable) {
return address(uint160(account));
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call.value(amount)("");
require(success, "Address: unable to send value, recipient may have reverted");
}
}
文件 4 的 51:CERC20Mock.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";
contract CERC20Mock is ERC20, ERC20Detailed {
address public dai;
uint256 internal _supplyRate;
uint256 internal _exchangeRate;
constructor(address _dai) public ERC20Detailed("cDAI", "cDAI", 8) {
dai = _dai;
uint256 daiDecimals = ERC20Detailed(_dai).decimals();
_exchangeRate = 2 * (10**(daiDecimals + 8));
_supplyRate = 45290900000;
}
function mint(uint256 amount) external returns (uint256) {
require(
ERC20(dai).transferFrom(msg.sender, address(this), amount),
"Error during transferFrom"
);
_mint(msg.sender, (amount * 10**18) / _exchangeRate);
return 0;
}
function redeemUnderlying(uint256 amount) external returns (uint256) {
_burn(msg.sender, (amount * 10**18) / _exchangeRate);
require(
ERC20(dai).transfer(msg.sender, amount),
"Error during transfer"
);
return 0;
}
function exchangeRateStored() external view returns (uint256) {
return _exchangeRate;
}
function exchangeRateCurrent() external view returns (uint256) {
return _exchangeRate;
}
function _setExchangeRateStored(uint256 _rate) external returns (uint256) {
_exchangeRate = _rate;
}
function supplyRatePerBlock() external view returns (uint256) {
return _supplyRate;
}
function _setSupplyRatePerBlock(uint256 _rate) external {
_supplyRate = _rate;
}
}
文件 5 的 51:CompoundERC20Market.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/ownership/Ownable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "../IMoneyMarket.sol";
import "../../libs/DecMath.sol";
import "./imports/ICERC20.sol";
import "./imports/IComptroller.sol";
contract CompoundERC20Market is IMoneyMarket, Ownable {
using DecMath for uint256;
using SafeERC20 for ERC20;
using Address for address;
uint256 internal constant ERRCODE_OK = 0;
ICERC20 public cToken;
IComptroller public comptroller;
address public rewards;
ERC20 public stablecoin;
constructor(
address _cToken,
address _comptroller,
address _rewards,
address _stablecoin
) public {
require(
_cToken != address(0) &&
_comptroller != address(0) &&
_rewards != address(0) &&
_stablecoin != address(0),
"CompoundERC20Market: An input address is 0"
);
require(
_cToken.isContract() &&
_comptroller.isContract() &&
_rewards.isContract() &&
_stablecoin.isContract(),
"CompoundERC20Market: An input address is not a contract"
);
cToken = ICERC20(_cToken);
comptroller = IComptroller(_comptroller);
rewards = _rewards;
stablecoin = ERC20(_stablecoin);
}
function deposit(uint256 amount) external onlyOwner {
require(amount > 0, "CompoundERC20Market: amount is 0");
stablecoin.safeTransferFrom(msg.sender, address(this), amount);
stablecoin.safeIncreaseAllowance(address(cToken), amount);
require(
cToken.mint(amount) == ERRCODE_OK,
"CompoundERC20Market: Failed to mint cTokens"
);
}
function withdraw(uint256 amountInUnderlying)
external
onlyOwner
returns (uint256 actualAmountWithdrawn)
{
require(
amountInUnderlying > 0,
"CompoundERC20Market: amountInUnderlying is 0"
);
require(
cToken.redeemUnderlying(amountInUnderlying) == ERRCODE_OK,
"CompoundERC20Market: Failed to redeem"
);
stablecoin.safeTransfer(msg.sender, amountInUnderlying);
return amountInUnderlying;
}
function claimRewards() external {
comptroller.claimComp(address(this));
ERC20 comp = ERC20(comptroller.getCompAddress());
comp.safeTransfer(rewards, comp.balanceOf(address(this)));
}
function totalValue() external returns (uint256) {
uint256 cTokenBalance = cToken.balanceOf(address(this));
uint256 cTokenPrice = cToken.exchangeRateCurrent();
return cTokenBalance.decmul(cTokenPrice);
}
function incomeIndex() external returns (uint256) {
return cToken.exchangeRateCurrent();
}
function setRewards(address newValue) external onlyOwner {
require(newValue.isContract(), "CompoundERC20Market: not contract");
rewards = newValue;
emit ESetParamAddress(msg.sender, "rewards", newValue);
}
}
文件 6 的 51:ComptrollerMock.sol
pragma solidity 0.5.17;
import "./ERC20Mock.sol";
contract ComptrollerMock {
uint256 public constant CLAIM_AMOUNT = 10**18;
ERC20Mock public comp;
constructor (address _comp) public {
comp = ERC20Mock(_comp);
}
function claimComp(address holder) external {
comp.mint(holder, CLAIM_AMOUNT);
}
function getCompAddress() external view returns (address) {
return address(comp);
}
}
文件 7 的 51:Context.sol
pragma solidity ^0.5.0;
contract Context {
constructor () internal { }
function _msgSender() internal view returns (address payable) {
return msg.sender;
}
function _msgData() internal view returns (bytes memory) {
this;
return msg.data;
}
}
文件 8 的 51:Counters.sol
pragma solidity ^0.5.0;
import "../math/SafeMath.sol";
library Counters {
using SafeMath for uint256;
struct Counter {
uint256 _value;
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
counter._value += 1;
}
function decrement(Counter storage counter) internal {
counter._value = counter._value.sub(1);
}
}
文件 9 的 51:DInterest.sol
pragma solidity 0.5.17;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/ownership/Ownable.sol";
import "./libs/DecMath.sol";
import "./moneymarkets/IMoneyMarket.sol";
import "./models/fee/IFeeModel.sol";
import "./models/interest/IInterestModel.sol";
import "./NFT.sol";
import "./rewards/MPHMinter.sol";
import "./models/interest-oracle/IInterestOracle.sol";
contract DInterest is ReentrancyGuard, Ownable {
using SafeMath for uint256;
using DecMath for uint256;
using SafeERC20 for ERC20;
using Address for address;
uint256 internal constant PRECISION = 10**18;
uint256 internal constant ONE = 10**18;
struct Deposit {
uint256 amount;
uint256 maturationTimestamp;
uint256 interestOwed;
uint256 initialMoneyMarketIncomeIndex;
bool active;
bool finalSurplusIsNegative;
uint256 finalSurplusAmount;
uint256 mintMPHAmount;
}
Deposit[] internal deposits;
uint256 public latestFundedDepositID;
uint256 public unfundedUserDepositAmount;
struct Funding {
uint256 fromDepositID;
uint256 toDepositID;
uint256 recordedFundedDepositAmount;
uint256 recordedMoneyMarketIncomeIndex;
}
Funding[] internal fundingList;
uint256 public MinDepositPeriod;
uint256 public MaxDepositPeriod;
uint256 public MinDepositAmount;
uint256 public MaxDepositAmount;
uint256 public totalDeposit;
uint256 public totalInterestOwed;
IMoneyMarket public moneyMarket;
ERC20 public stablecoin;
IFeeModel public feeModel;
IInterestModel public interestModel;
IInterestOracle public interestOracle;
NFT public depositNFT;
NFT public fundingNFT;
MPHMinter public mphMinter;
event EDeposit(
address indexed sender,
uint256 indexed depositID,
uint256 amount,
uint256 maturationTimestamp,
uint256 interestAmount,
uint256 mintMPHAmount
);
event EWithdraw(
address indexed sender,
uint256 indexed depositID,
uint256 indexed fundingID,
bool early,
uint256 takeBackMPHAmount
);
event EFund(
address indexed sender,
uint256 indexed fundingID,
uint256 deficitAmount,
uint256 mintMPHAmount
);
event ESetParamAddress(
address indexed sender,
string indexed paramName,
address newValue
);
event ESetParamUint(
address indexed sender,
string indexed paramName,
uint256 newValue
);
struct DepositLimit {
uint256 MinDepositPeriod;
uint256 MaxDepositPeriod;
uint256 MinDepositAmount;
uint256 MaxDepositAmount;
}
constructor(
DepositLimit memory _depositLimit,
address _moneyMarket,
address _stablecoin,
address _feeModel,
address _interestModel,
address _interestOracle,
address _depositNFT,
address _fundingNFT,
address _mphMinter
) public {
require(
_moneyMarket.isContract() &&
_stablecoin.isContract() &&
_feeModel.isContract() &&
_interestModel.isContract() &&
_interestOracle.isContract() &&
_depositNFT.isContract() &&
_fundingNFT.isContract() &&
_mphMinter.isContract(),
"DInterest: An input address is not a contract"
);
moneyMarket = IMoneyMarket(_moneyMarket);
stablecoin = ERC20(_stablecoin);
feeModel = IFeeModel(_feeModel);
interestModel = IInterestModel(_interestModel);
interestOracle = IInterestOracle(_interestOracle);
depositNFT = NFT(_depositNFT);
fundingNFT = NFT(_fundingNFT);
mphMinter = MPHMinter(_mphMinter);
require(
moneyMarket.stablecoin() == _stablecoin,
"DInterest: moneyMarket.stablecoin() != _stablecoin"
);
require(
interestOracle.moneyMarket() == _moneyMarket,
"DInterest: interestOracle.moneyMarket() != _moneyMarket"
);
require(
_depositLimit.MaxDepositPeriod > 0 &&
_depositLimit.MaxDepositAmount > 0,
"DInterest: An input uint256 is 0"
);
require(
_depositLimit.MinDepositPeriod <= _depositLimit.MaxDepositPeriod,
"DInterest: Invalid DepositPeriod range"
);
require(
_depositLimit.MinDepositAmount <= _depositLimit.MaxDepositAmount,
"DInterest: Invalid DepositAmount range"
);
MinDepositPeriod = _depositLimit.MinDepositPeriod;
MaxDepositPeriod = _depositLimit.MaxDepositPeriod;
MinDepositAmount = _depositLimit.MinDepositAmount;
MaxDepositAmount = _depositLimit.MaxDepositAmount;
totalDeposit = 0;
}
function deposit(uint256 amount, uint256 maturationTimestamp)
external
nonReentrant
{
_deposit(amount, maturationTimestamp);
}
function withdraw(uint256 depositID, uint256 fundingID)
external
nonReentrant
{
_withdraw(depositID, fundingID, false);
}
function earlyWithdraw(uint256 depositID, uint256 fundingID)
external
nonReentrant
{
_withdraw(depositID, fundingID, true);
}
function multiDeposit(
uint256[] calldata amountList,
uint256[] calldata maturationTimestampList
) external nonReentrant {
require(
amountList.length == maturationTimestampList.length,
"DInterest: List lengths unequal"
);
for (uint256 i = 0; i < amountList.length; i = i.add(1)) {
_deposit(amountList[i], maturationTimestampList[i]);
}
}
function multiWithdraw(
uint256[] calldata depositIDList,
uint256[] calldata fundingIDList
) external nonReentrant {
require(
depositIDList.length == fundingIDList.length,
"DInterest: List lengths unequal"
);
for (uint256 i = 0; i < depositIDList.length; i = i.add(1)) {
_withdraw(depositIDList[i], fundingIDList[i], false);
}
}
function multiEarlyWithdraw(
uint256[] calldata depositIDList,
uint256[] calldata fundingIDList
) external nonReentrant {
require(
depositIDList.length == fundingIDList.length,
"DInterest: List lengths unequal"
);
for (uint256 i = 0; i < depositIDList.length; i = i.add(1)) {
_withdraw(depositIDList[i], fundingIDList[i], true);
}
}
function fundAll() external nonReentrant {
(bool isNegative, uint256 deficit) = surplus();
require(isNegative, "DInterest: No deficit available");
require(
!depositIsFunded(deposits.length),
"DInterest: All deposits funded"
);
uint256 incomeIndex = moneyMarket.incomeIndex();
require(incomeIndex > 0, "DInterest: incomeIndex == 0");
fundingList.push(
Funding({
fromDepositID: latestFundedDepositID,
toDepositID: deposits.length,
recordedFundedDepositAmount: unfundedUserDepositAmount,
recordedMoneyMarketIncomeIndex: incomeIndex
})
);
latestFundedDepositID = deposits.length;
unfundedUserDepositAmount = 0;
_fund(deficit);
}
function fundMultiple(uint256 toDepositID) external nonReentrant {
require(
toDepositID > latestFundedDepositID,
"DInterest: Deposits already funded"
);
require(
toDepositID <= deposits.length,
"DInterest: Invalid toDepositID"
);
(bool isNegative, uint256 surplus) = surplus();
require(isNegative, "DInterest: No deficit available");
uint256 totalDeficit = 0;
uint256 totalSurplus = 0;
uint256 totalDepositToFund = 0;
for (
uint256 id = latestFundedDepositID.add(1);
id <= toDepositID;
id = id.add(1)
) {
Deposit storage depositEntry = _getDeposit(id);
if (depositEntry.active) {
(isNegative, surplus) = surplusOfDeposit(id);
} else {
(isNegative, surplus) = (
depositEntry.finalSurplusIsNegative,
depositEntry.finalSurplusAmount
);
}
if (isNegative) {
totalDeficit = totalDeficit.add(surplus);
} else {
totalSurplus = totalSurplus.add(surplus);
}
if (depositEntry.active) {
totalDepositToFund = totalDepositToFund.add(
depositEntry.amount
);
}
}
if (totalSurplus >= totalDeficit) {
revert("DInterest: Selected deposits in surplus");
} else {
totalDeficit = totalDeficit.sub(totalSurplus);
}
uint256 incomeIndex = moneyMarket.incomeIndex();
require(incomeIndex > 0, "DInterest: incomeIndex == 0");
fundingList.push(
Funding({
fromDepositID: latestFundedDepositID,
toDepositID: toDepositID,
recordedFundedDepositAmount: totalDepositToFund,
recordedMoneyMarketIncomeIndex: incomeIndex
})
);
latestFundedDepositID = toDepositID;
unfundedUserDepositAmount = unfundedUserDepositAmount.sub(
totalDepositToFund
);
_fund(totalDeficit);
}
function calculateInterestAmount(
uint256 depositAmount,
uint256 depositPeriodInSeconds
) public returns (uint256 interestAmount) {
(, uint256 moneyMarketInterestRatePerSecond) = interestOracle
.updateAndQuery();
(bool surplusIsNegative, uint256 surplusAmount) = surplus();
return
interestModel.calculateInterestAmount(
depositAmount,
depositPeriodInSeconds,
moneyMarketInterestRatePerSecond,
surplusIsNegative,
surplusAmount
);
}
function surplus() public returns (bool isNegative, uint256 surplusAmount) {
uint256 totalValue = moneyMarket.totalValue();
uint256 totalOwed = totalDeposit.add(totalInterestOwed);
if (totalValue >= totalOwed) {
isNegative = false;
surplusAmount = totalValue.sub(totalOwed);
} else {
isNegative = true;
surplusAmount = totalOwed.sub(totalValue);
}
}
function surplusOfDeposit(uint256 depositID)
public
returns (bool isNegative, uint256 surplusAmount)
{
Deposit storage depositEntry = _getDeposit(depositID);
uint256 currentMoneyMarketIncomeIndex = moneyMarket.incomeIndex();
uint256 currentDepositValue = depositEntry
.amount
.mul(currentMoneyMarketIncomeIndex)
.div(depositEntry.initialMoneyMarketIncomeIndex);
uint256 owed = depositEntry.amount.add(depositEntry.interestOwed);
if (currentDepositValue >= owed) {
isNegative = false;
surplusAmount = currentDepositValue.sub(owed);
} else {
isNegative = true;
surplusAmount = owed.sub(currentDepositValue);
}
}
function depositIsFunded(uint256 id) public view returns (bool) {
return (id <= latestFundedDepositID);
}
function depositsLength() external view returns (uint256) {
return deposits.length;
}
function fundingListLength() external view returns (uint256) {
return fundingList.length;
}
function getDeposit(uint256 depositID)
external
view
returns (Deposit memory)
{
return deposits[depositID.sub(1)];
}
function getFunding(uint256 fundingID)
external
view
returns (Funding memory)
{
return fundingList[fundingID.sub(1)];
}
function moneyMarketIncomeIndex() external returns (uint256) {
return moneyMarket.incomeIndex();
}
function setFeeModel(address newValue) external onlyOwner {
require(newValue.isContract(), "DInterest: not contract");
feeModel = IFeeModel(newValue);
emit ESetParamAddress(msg.sender, "feeModel", newValue);
}
function setInterestModel(address newValue) external onlyOwner {
require(newValue.isContract(), "DInterest: not contract");
interestModel = IInterestModel(newValue);
emit ESetParamAddress(msg.sender, "interestModel", newValue);
}
function setInterestOracle(address newValue) external onlyOwner {
require(newValue.isContract(), "DInterest: not contract");
interestOracle = IInterestOracle(newValue);
emit ESetParamAddress(msg.sender, "interestOracle", newValue);
}
function setRewards(address newValue) external onlyOwner {
require(newValue.isContract(), "DInterest: not contract");
moneyMarket.setRewards(newValue);
emit ESetParamAddress(msg.sender, "moneyMarket.rewards", newValue);
}
function setMinDepositPeriod(uint256 newValue) external onlyOwner {
require(newValue <= MaxDepositPeriod, "DInterest: invalid value");
MinDepositPeriod = newValue;
emit ESetParamUint(msg.sender, "MinDepositPeriod", newValue);
}
function setMaxDepositPeriod(uint256 newValue) external onlyOwner {
require(
newValue >= MinDepositPeriod && newValue > 0,
"DInterest: invalid value"
);
MaxDepositPeriod = newValue;
emit ESetParamUint(msg.sender, "MaxDepositPeriod", newValue);
}
function setMinDepositAmount(uint256 newValue) external onlyOwner {
require(newValue <= MaxDepositAmount, "DInterest: invalid value");
MinDepositAmount = newValue;
emit ESetParamUint(msg.sender, "MinDepositAmount", newValue);
}
function setMaxDepositAmount(uint256 newValue) external onlyOwner {
require(
newValue >= MinDepositAmount && newValue > 0,
"DInterest: invalid value"
);
MaxDepositAmount = newValue;
emit ESetParamUint(msg.sender, "MaxDepositAmount", newValue);
}
function setDepositNFTTokenURI(uint256 tokenId, string calldata newURI)
external
onlyOwner
{
depositNFT.setTokenURI(tokenId, newURI);
}
function setDepositNFTBaseURI(string calldata newURI) external onlyOwner {
depositNFT.setBaseURI(newURI);
}
function setDepositNFTContractURI(string calldata newURI)
external
onlyOwner
{
depositNFT.setContractURI(newURI);
}
function setFundingNFTTokenURI(uint256 tokenId, string calldata newURI)
external
onlyOwner
{
fundingNFT.setTokenURI(tokenId, newURI);
}
function setFundingNFTBaseURI(string calldata newURI) external onlyOwner {
fundingNFT.setBaseURI(newURI);
}
function setFundingNFTContractURI(string calldata newURI)
external
onlyOwner
{
fundingNFT.setContractURI(newURI);
}
function _getDeposit(uint256 depositID)
internal
view
returns (Deposit storage)
{
return deposits[depositID.sub(1)];
}
function _getFunding(uint256 fundingID)
internal
view
returns (Funding storage)
{
return fundingList[fundingID.sub(1)];
}
function _deposit(uint256 amount, uint256 maturationTimestamp) internal {
require(amount > 0, "DInterest: Deposit amount is 0");
require(
amount >= MinDepositAmount && amount <= MaxDepositAmount,
"DInterest: Deposit amount out of range"
);
uint256 depositPeriod = maturationTimestamp.sub(now);
require(
depositPeriod >= MinDepositPeriod &&
depositPeriod <= MaxDepositPeriod,
"DInterest: Deposit period out of range"
);
totalDeposit = totalDeposit.add(amount);
uint256 id = deposits.length.add(1);
unfundedUserDepositAmount = unfundedUserDepositAmount.add(amount);
uint256 interestAmount = calculateInterestAmount(amount, depositPeriod);
require(interestAmount > 0, "DInterest: interestAmount == 0");
totalInterestOwed = totalInterestOwed.add(interestAmount);
uint256 mintMPHAmount = mphMinter.mintDepositorReward(
msg.sender,
interestAmount
);
deposits.push(
Deposit({
amount: amount,
maturationTimestamp: maturationTimestamp,
interestOwed: interestAmount,
initialMoneyMarketIncomeIndex: moneyMarket.incomeIndex(),
active: true,
finalSurplusIsNegative: false,
finalSurplusAmount: 0,
mintMPHAmount: mintMPHAmount
})
);
stablecoin.safeTransferFrom(msg.sender, address(this), amount);
stablecoin.safeIncreaseAllowance(address(moneyMarket), amount);
moneyMarket.deposit(amount);
depositNFT.mint(msg.sender, id);
emit EDeposit(
msg.sender,
id,
amount,
maturationTimestamp,
interestAmount,
mintMPHAmount
);
}
function _withdraw(
uint256 depositID,
uint256 fundingID,
bool early
) internal {
Deposit storage depositEntry = _getDeposit(depositID);
require(depositEntry.active, "DInterest: Deposit not active");
depositEntry.active = false;
if (early) {
require(
now < depositEntry.maturationTimestamp,
"DInterest: Deposit mature, use withdraw() instead"
);
} else {
require(
now >= depositEntry.maturationTimestamp,
"DInterest: Deposit not mature"
);
}
require(
depositNFT.ownerOf(depositID) == msg.sender,
"DInterest: Sender doesn't own depositNFT"
);
uint256 takeBackMPHAmount = mphMinter.takeBackDepositorReward(
msg.sender,
depositEntry.mintMPHAmount,
early
);
totalDeposit = totalDeposit.sub(depositEntry.amount);
totalInterestOwed = totalInterestOwed.sub(depositEntry.interestOwed);
depositNFT.burn(depositID);
uint256 feeAmount;
uint256 withdrawAmount;
if (early) {
withdrawAmount = depositEntry.amount;
} else {
feeAmount = feeModel.getFee(depositEntry.interestOwed);
withdrawAmount = depositEntry.amount.add(depositEntry.interestOwed);
}
withdrawAmount = moneyMarket.withdraw(withdrawAmount);
(bool depositIsNegative, uint256 depositSurplus) = surplusOfDeposit(
depositID
);
if (depositIsFunded(depositID)) {
Funding storage f = _getFunding(fundingID);
require(
depositID > f.fromDepositID && depositID <= f.toDepositID,
"DInterest: Deposit not funded by fundingID"
);
uint256 currentMoneyMarketIncomeIndex = moneyMarket.incomeIndex();
require(
currentMoneyMarketIncomeIndex > 0,
"DInterest: currentMoneyMarketIncomeIndex == 0"
);
uint256 interestAmount = f
.recordedFundedDepositAmount
.mul(currentMoneyMarketIncomeIndex)
.div(f.recordedMoneyMarketIncomeIndex)
.sub(f.recordedFundedDepositAmount);
f.recordedFundedDepositAmount = f.recordedFundedDepositAmount.sub(
depositEntry.amount
);
f.recordedMoneyMarketIncomeIndex = currentMoneyMarketIncomeIndex;
uint256 transferToFunderAmount = (early && depositIsNegative)
? interestAmount.add(depositSurplus)
: interestAmount;
if (transferToFunderAmount > 0) {
transferToFunderAmount = moneyMarket.withdraw(
transferToFunderAmount
);
stablecoin.safeTransfer(
fundingNFT.ownerOf(fundingID),
transferToFunderAmount
);
}
} else {
unfundedUserDepositAmount = unfundedUserDepositAmount.sub(
depositEntry.amount
);
depositEntry.finalSurplusIsNegative = depositIsNegative;
depositEntry.finalSurplusAmount = depositSurplus;
}
stablecoin.safeTransfer(msg.sender, withdrawAmount.sub(feeAmount));
stablecoin.safeTransfer(feeModel.beneficiary(), feeAmount);
emit EWithdraw(
msg.sender,
depositID,
fundingID,
early,
takeBackMPHAmount
);
}
function _fund(uint256 totalDeficit) internal {
stablecoin.safeTransferFrom(msg.sender, address(this), totalDeficit);
stablecoin.safeIncreaseAllowance(address(moneyMarket), totalDeficit);
moneyMarket.deposit(totalDeficit);
fundingNFT.mint(msg.sender, fundingList.length);
uint256 mintMPHAmount = mphMinter.mintFunderReward(
msg.sender,
totalDeficit
);
uint256 fundingID = fundingList.length;
emit EFund(msg.sender, fundingID, totalDeficit, mintMPHAmount);
}
}
文件 10 的 51:DecMath.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/math/SafeMath.sol";
library DecMath {
using SafeMath for uint256;
uint256 internal constant PRECISION = 10**18;
function decmul(uint256 a, uint256 b) internal pure returns (uint256) {
return a.mul(b).div(PRECISION);
}
function decdiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a.mul(PRECISION).div(b);
}
}
文件 11 的 51:EMAOracle.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../../moneymarkets/IMoneyMarket.sol";
import "../../libs/DecMath.sol";
import "./IInterestOracle.sol";
contract EMAOracle is IInterestOracle {
using SafeMath for uint256;
using DecMath for uint256;
uint256 internal constant PRECISION = 10**18;
uint256 public UPDATE_INTERVAL;
uint256 public UPDATE_MULTIPLIER;
uint256 public ONE_MINUS_UPDATE_MULTIPLIER;
uint256 public emaStored;
uint256 public lastIncomeIndex;
uint256 public lastUpdateTimestamp;
IMoneyMarket public moneyMarket;
constructor(
uint256 _emaInitial,
uint256 _updateInterval,
uint256 _smoothingFactor,
uint256 _averageWindowInIntervals,
address _moneyMarket
) public {
emaStored = _emaInitial;
UPDATE_INTERVAL = _updateInterval;
lastUpdateTimestamp = now;
uint256 updateMultiplier = _smoothingFactor.div(_averageWindowInIntervals.add(1));
UPDATE_MULTIPLIER = updateMultiplier;
ONE_MINUS_UPDATE_MULTIPLIER = PRECISION.sub(updateMultiplier);
moneyMarket = IMoneyMarket(_moneyMarket);
lastIncomeIndex = moneyMarket.incomeIndex();
}
function updateAndQuery() public returns (bool updated, uint256 value) {
uint256 timeElapsed = now - lastUpdateTimestamp;
if (timeElapsed < UPDATE_INTERVAL) {
return (false, emaStored);
}
uint256 _lastIncomeIndex = lastIncomeIndex;
uint256 _emaStored = emaStored;
uint256 newIncomeIndex = moneyMarket.incomeIndex();
uint256 incomingValue = newIncomeIndex.sub(_lastIncomeIndex).decdiv(_lastIncomeIndex).div(timeElapsed);
updated = true;
value = incomingValue.mul(UPDATE_MULTIPLIER).add(_emaStored.mul(ONE_MINUS_UPDATE_MULTIPLIER)).div(PRECISION);
emaStored = value;
lastIncomeIndex = newIncomeIndex;
lastUpdateTimestamp = now;
}
function query() public view returns (uint256 value) {
return emaStored;
}
}
文件 12 的 51:ERC165.sol
pragma solidity ^0.5.0;
import "./IERC165.sol";
contract ERC165 is IERC165 {
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
mapping(bytes4 => bool) private _supportedInterfaces;
constructor () internal {
_registerInterface(_INTERFACE_ID_ERC165);
}
function supportsInterface(bytes4 interfaceId) external view returns (bool) {
return _supportedInterfaces[interfaceId];
}
function _registerInterface(bytes4 interfaceId) internal {
require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
_supportedInterfaces[interfaceId] = true;
}
}
文件 13 的 51:ERC20.sol
pragma solidity ^0.5.0;
import "../../GSN/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.sol";
contract ERC20 is Context, IERC20 {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint256 amount) public returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
function _transfer(address sender, address recipient, uint256 amount) internal {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
function _mint(address account, uint256 amount) internal {
require(account != address(0), "ERC20: mint to the zero address");
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal {
require(account != address(0), "ERC20: burn from the zero address");
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal {
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);
}
function _burnFrom(address account, uint256 amount) internal {
_burn(account, amount);
_approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance"));
}
}
文件 14 的 51:ERC20Detailed.sol
pragma solidity ^0.5.0;
import "./IERC20.sol";
contract ERC20Detailed is IERC20 {
string private _name;
string private _symbol;
uint8 private _decimals;
constructor (string memory name, string memory symbol, uint8 decimals) public {
_name = name;
_symbol = symbol;
_decimals = decimals;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view returns (uint8) {
return _decimals;
}
}
文件 15 的 51:ERC20Mock.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";
contract ERC20Mock is ERC20, ERC20Detailed("", "", 6) {
function mint(address to, uint256 amount) public {
_mint(to, amount);
}
}
文件 16 的 51:ERC721.sol
pragma solidity ^0.5.0;
import "../../GSN/Context.sol";
import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
import "../../drafts/Counters.sol";
import "../../introspection/ERC165.sol";
contract ERC721 is Context, ERC165, IERC721 {
using SafeMath for uint256;
using Address for address;
using Counters for Counters.Counter;
bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
mapping (uint256 => address) private _tokenOwner;
mapping (uint256 => address) private _tokenApprovals;
mapping (address => Counters.Counter) private _ownedTokensCount;
mapping (address => mapping (address => bool)) private _operatorApprovals;
bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
constructor () public {
_registerInterface(_INTERFACE_ID_ERC721);
}
function balanceOf(address owner) public view returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _ownedTokensCount[owner].current();
}
function ownerOf(uint256 tokenId) public view returns (address) {
address owner = _tokenOwner[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
function approve(address to, uint256 tokenId) public {
address owner = ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not owner nor approved for all"
);
_tokenApprovals[tokenId] = to;
emit Approval(owner, to, tokenId);
}
function getApproved(uint256 tokenId) public view returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address to, bool approved) public {
require(to != _msgSender(), "ERC721: approve to caller");
_operatorApprovals[_msgSender()][to] = approved;
emit ApprovalForAll(_msgSender(), to, approved);
}
function isApprovedForAll(address owner, address operator) public view returns (bool) {
return _operatorApprovals[owner][operator];
}
function transferFrom(address from, address to, uint256 tokenId) public {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transferFrom(from, to, tokenId);
}
function safeTransferFrom(address from, address to, uint256 tokenId) public {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransferFrom(from, to, tokenId, _data);
}
function _safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) internal {
_transferFrom(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
function _exists(uint256 tokenId) internal view returns (bool) {
address owner = _tokenOwner[tokenId];
return owner != address(0);
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
function _safeMint(address to, uint256 tokenId) internal {
_safeMint(to, tokenId, "");
}
function _safeMint(address to, uint256 tokenId, bytes memory _data) internal {
_mint(to, tokenId);
require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
function _mint(address to, uint256 tokenId) internal {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_tokenOwner[tokenId] = to;
_ownedTokensCount[to].increment();
emit Transfer(address(0), to, tokenId);
}
function _burn(address owner, uint256 tokenId) internal {
require(ownerOf(tokenId) == owner, "ERC721: burn of token that is not own");
_clearApproval(tokenId);
_ownedTokensCount[owner].decrement();
_tokenOwner[tokenId] = address(0);
emit Transfer(owner, address(0), tokenId);
}
function _burn(uint256 tokenId) internal {
_burn(ownerOf(tokenId), tokenId);
}
function _transferFrom(address from, address to, uint256 tokenId) internal {
require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
_clearApproval(tokenId);
_ownedTokensCount[from].decrement();
_ownedTokensCount[to].increment();
_tokenOwner[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
internal returns (bool)
{
if (!to.isContract()) {
return true;
}
(bool success, bytes memory returndata) = to.call(abi.encodeWithSelector(
IERC721Receiver(to).onERC721Received.selector,
_msgSender(),
from,
tokenId,
_data
));
if (!success) {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert("ERC721: transfer to non ERC721Receiver implementer");
}
} else {
bytes4 retval = abi.decode(returndata, (bytes4));
return (retval == _ERC721_RECEIVED);
}
}
function _clearApproval(uint256 tokenId) private {
if (_tokenApprovals[tokenId] != address(0)) {
_tokenApprovals[tokenId] = address(0);
}
}
}
文件 17 的 51:ERC721Metadata.sol
pragma solidity ^0.5.0;
import "../../GSN/Context.sol";
import "./ERC721.sol";
import "./IERC721Metadata.sol";
import "../../introspection/ERC165.sol";
contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
string private _name;
string private _symbol;
string private _baseURI;
mapping(uint256 => string) private _tokenURIs;
bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
constructor (string memory name, string memory symbol) public {
_name = name;
_symbol = symbol;
_registerInterface(_INTERFACE_ID_ERC721_METADATA);
}
function name() external view returns (string memory) {
return _name;
}
function symbol() external view returns (string memory) {
return _symbol;
}
function tokenURI(uint256 tokenId) external view returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory _tokenURI = _tokenURIs[tokenId];
if (bytes(_tokenURI).length == 0) {
return "";
} else {
return string(abi.encodePacked(_baseURI, _tokenURI));
}
}
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal {
require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
function _setBaseURI(string memory baseURI) internal {
_baseURI = baseURI;
}
function baseURI() external view returns (string memory) {
return _baseURI;
}
function _burn(address owner, uint256 tokenId) internal {
super._burn(owner, tokenId);
if (bytes(_tokenURIs[tokenId]).length != 0) {
delete _tokenURIs[tokenId];
}
}
}
文件 18 的 51:IAToken.sol
pragma solidity 0.5.17;
interface IAToken {
function redeem(uint256 _amount) external;
function balanceOf(address owner) external view returns (uint256);
}
文件 19 的 51:ICERC20.sol
pragma solidity 0.5.17;
interface ICERC20 {
function transfer(address dst, uint256 amount) external returns (bool);
function transferFrom(address src, address dst, uint256 amount)
external
returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender)
external
view
returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function balanceOfUnderlying(address owner) external returns (uint256);
function getAccountSnapshot(address account)
external
view
returns (uint256, uint256, uint256, uint256);
function borrowRatePerBlock() external view returns (uint256);
function supplyRatePerBlock() external view returns (uint256);
function totalBorrowsCurrent() external returns (uint256);
function borrowBalanceCurrent(address account) external returns (uint256);
function borrowBalanceStored(address account)
external
view
returns (uint256);
function exchangeRateCurrent() external returns (uint256);
function exchangeRateStored() external view returns (uint256);
function getCash() external view returns (uint256);
function accrueInterest() external returns (uint256);
function seize(address liquidator, address borrower, uint256 seizeTokens)
external
returns (uint256);
function mint(uint256 mintAmount) external returns (uint256);
function redeem(uint256 redeemTokens) external returns (uint256);
function redeemUnderlying(uint256 redeemAmount) external returns (uint256);
function borrow(uint256 borrowAmount) external returns (uint256);
function repayBorrow(uint256 repayAmount) external returns (uint256);
function repayBorrowBehalf(address borrower, uint256 repayAmount)
external
returns (uint256);
function liquidateBorrow(
address borrower,
uint256 repayAmount,
address cTokenCollateral
) external returns (uint256);
}
文件 20 的 51:IComptroller.sol
pragma solidity 0.5.17;
interface IComptroller {
function claimComp(address holder) external;
function getCompAddress() external view returns (address);
}
文件 21 的 51:IERC165.sol
pragma solidity ^0.5.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 22 的 51:IERC20.sol
pragma solidity ^0.5.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 23 的 51:IERC721.sol
pragma solidity ^0.5.0;
import "../../introspection/IERC165.sol";
contract IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) public view returns (uint256 balance);
function ownerOf(uint256 tokenId) public view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId) public;
function transferFrom(address from, address to, uint256 tokenId) public;
function approve(address to, uint256 tokenId) public;
function getApproved(uint256 tokenId) public view returns (address operator);
function setApprovalForAll(address operator, bool _approved) public;
function isApprovedForAll(address owner, address operator) public view returns (bool);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
}
文件 24 的 51:IERC721Metadata.sol
pragma solidity ^0.5.0;
import "./IERC721.sol";
contract IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
文件 25 的 51:IERC721Receiver.sol
pragma solidity ^0.5.0;
contract IERC721Receiver {
function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
public returns (bytes4);
}
文件 26 的 51:IFeeModel.sol
pragma solidity 0.5.17;
interface IFeeModel {
function beneficiary() external view returns (address payable);
function getFee(uint256 _txAmount)
external
pure
returns (uint256 _feeAmount);
}
文件 27 的 51:IInterestModel.sol
pragma solidity 0.5.17;
interface IInterestModel {
function calculateInterestAmount(
uint256 depositAmount,
uint256 depositPeriodInSeconds,
uint256 moneyMarketInterestRatePerSecond,
bool surplusIsNegative,
uint256 surplusAmount
) external view returns (uint256 interestAmount);
}
文件 28 的 51:IInterestOracle.sol
pragma solidity 0.5.17;
interface IInterestOracle {
function updateAndQuery() external returns (bool updated, uint256 value);
function query() external view returns (uint256 value);
function moneyMarket() external view returns (address);
}
文件 29 的 51:ILendingPool.sol
pragma solidity 0.5.17;
interface ILendingPool {
function deposit(address _reserve, uint256 _amount, uint16 _referralCode)
external;
function getReserveData(address _reserve)
external
view
returns (
uint256 totalLiquidity,
uint256 availableLiquidity,
uint256 totalBorrowsStable,
uint256 totalBorrowsVariable,
uint256 liquidityRate,
uint256 variableBorrowRate,
uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 utilizationRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex,
address aTokenAddress,
uint40 lastUpdateTimestamp
);
}
文件 30 的 51:ILendingPoolAddressesProvider.sol
pragma solidity 0.5.17;
interface ILendingPoolAddressesProvider {
function getLendingPool() external view returns (address);
function setLendingPoolImpl(address _pool) external;
function getLendingPoolCore() external view returns (address payable);
function setLendingPoolCoreImpl(address _lendingPoolCore) external;
function getLendingPoolConfigurator() external view returns (address);
function setLendingPoolConfiguratorImpl(address _configurator) external;
function getLendingPoolDataProvider() external view returns (address);
function setLendingPoolDataProviderImpl(address _provider) external;
function getLendingPoolParametersProvider() external view returns (address);
function setLendingPoolParametersProviderImpl(address _parametersProvider)
external;
function getTokenDistributor() external view returns (address);
function setTokenDistributor(address _tokenDistributor) external;
function getFeeProvider() external view returns (address);
function setFeeProviderImpl(address _feeProvider) external;
function getLendingPoolLiquidationManager() external view returns (address);
function setLendingPoolLiquidationManager(address _manager) external;
function getLendingPoolManager() external view returns (address);
function setLendingPoolManager(address _lendingPoolManager) external;
function getPriceOracle() external view returns (address);
function setPriceOracle(address _priceOracle) external;
function getLendingRateOracle() external view returns (address);
function setLendingRateOracle(address _lendingRateOracle) external;
}
文件 31 的 51:ILendingPoolCore.sol
pragma solidity 0.5.17;
interface ILendingPoolCore {
function getReserveNormalizedIncome(address _reserve)
external
view
returns (uint256);
}
文件 32 的 51:IMoneyMarket.sol
pragma solidity 0.5.17;
interface IMoneyMarket {
function deposit(uint256 amount) external;
function withdraw(uint256 amountInUnderlying)
external
returns (uint256 actualAmountWithdrawn);
function claimRewards() external;
function totalValue() external returns (uint256);
function incomeIndex() external returns (uint256);
function stablecoin() external view returns (address);
function setRewards(address newValue) external;
event ESetParamAddress(
address indexed sender,
string indexed paramName,
address newValue
);
}
文件 33 的 51:IRewards.sol
pragma solidity 0.5.17;
interface IRewards {
function notifyRewardAmount(uint256 reward) external;
}
文件 34 的 51:LendingPoolAddressesProviderMock.sol
pragma solidity 0.5.17;
contract LendingPoolAddressesProviderMock {
address internal pool;
address internal core;
function getLendingPool() external view returns (address) {
return pool;
}
function setLendingPoolImpl(address _pool) external {
pool = _pool;
}
function getLendingPoolCore() external view returns (address) {
return core;
}
function setLendingPoolCoreImpl(address _pool) external {
core = _pool;
}
}
文件 35 的 51:LendingPoolCoreMock.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "./ATokenMock.sol";
import "./LendingPoolMock.sol";
contract LendingPoolCoreMock {
LendingPoolMock internal lendingPool;
function setLendingPool(address lendingPoolAddress) public {
lendingPool = LendingPoolMock(lendingPoolAddress);
}
function bounceTransfer(address _reserve, address _sender, uint256 _amount)
external
{
ERC20 token = ERC20(_reserve);
token.transferFrom(_sender, address(this), _amount);
token.transfer(msg.sender, _amount);
}
function getReserveNormalizedIncome(address _reserve) external view returns (uint256) {
(, , , , , , , , , , , address aTokenAddress, ) = lendingPool
.getReserveData(_reserve);
ATokenMock aToken = ATokenMock(aTokenAddress);
return aToken.normalizedIncome();
}
}
文件 36 的 51:LendingPoolMock.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "./ATokenMock.sol";
import "./LendingPoolCoreMock.sol";
contract LendingPoolMock {
mapping(address => address) internal reserveAToken;
LendingPoolCoreMock public core;
constructor(address _core) public {
core = LendingPoolCoreMock(_core);
}
function setReserveAToken(address _reserve, address _aTokenAddress) external {
reserveAToken[_reserve] = _aTokenAddress;
}
function deposit(address _reserve, uint256 _amount, uint16)
external
{
ERC20 token = ERC20(_reserve);
core.bounceTransfer(_reserve, msg.sender, _amount);
address aTokenAddress = reserveAToken[_reserve];
ATokenMock aToken = ATokenMock(aTokenAddress);
aToken.mint(msg.sender, _amount);
token.transfer(aTokenAddress, _amount);
}
function getReserveData(address _reserve)
external
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256 liquidityRate,
uint256,
uint256,
uint256,
uint256,
uint256,
uint256,
address aTokenAddress,
uint40
)
{
aTokenAddress = reserveAToken[_reserve];
ATokenMock aToken = ATokenMock(aTokenAddress);
liquidityRate = aToken.liquidityRate();
}
}
文件 37 的 51:LinearInterestModel.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../../libs/DecMath.sol";
contract LinearInterestModel {
using SafeMath for uint256;
using DecMath for uint256;
uint256 public constant PRECISION = 10**18;
uint256 public IRMultiplier;
constructor(uint256 _IRMultiplier) public {
IRMultiplier = _IRMultiplier;
}
function calculateInterestAmount(
uint256 depositAmount,
uint256 depositPeriodInSeconds,
uint256 moneyMarketInterestRatePerSecond,
bool,
uint256
) external view returns (uint256 interestAmount) {
interestAmount = depositAmount
.mul(PRECISION)
.decmul(moneyMarketInterestRatePerSecond)
.decmul(IRMultiplier)
.mul(depositPeriodInSeconds)
.div(PRECISION);
}
}
文件 38 的 51:MPHMinter.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/ownership/Ownable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "../libs/DecMath.sol";
import "./MPHToken.sol";
contract MPHMinter is Ownable {
using Address for address;
using DecMath for uint256;
using SafeMath for uint256;
uint256 internal constant PRECISION = 10**18;
mapping(address => uint256) public poolMintingMultiplier;
mapping(address => uint256) public poolDepositorRewardMultiplier;
mapping(address => uint256) public poolFunderRewardMultiplier;
uint256 public devRewardMultiplier;
event ESetParamAddress(
address indexed sender,
string indexed paramName,
address newValue
);
event ESetParamUint(
address indexed sender,
string indexed paramName,
uint256 newValue
);
MPHToken public mph;
address public govTreasury;
address public devWallet;
constructor(
address _mph,
address _govTreasury,
address _devWallet,
uint256 _devRewardMultiplier
) public {
mph = MPHToken(_mph);
govTreasury = _govTreasury;
devWallet = _devWallet;
devRewardMultiplier = _devRewardMultiplier;
}
function mintDepositorReward(address to, uint256 interestAmount)
external
returns (uint256)
{
uint256 multiplier = poolMintingMultiplier[msg.sender];
uint256 mintAmount = interestAmount.decmul(multiplier);
if (mintAmount == 0) {
return 0;
}
mph.ownerMint(to, mintAmount);
mph.ownerMint(devWallet, mintAmount.decmul(devRewardMultiplier));
return mintAmount;
}
function mintFunderReward(address to, uint256 interestAmount)
external
returns (uint256)
{
uint256 multiplier = poolMintingMultiplier[msg.sender].decmul(
poolFunderRewardMultiplier[msg.sender]
);
uint256 mintAmount = interestAmount.decmul(multiplier);
if (mintAmount == 0) {
return 0;
}
mph.ownerMint(to, mintAmount);
mph.ownerMint(devWallet, mintAmount.decmul(devRewardMultiplier));
return mintAmount;
}
function takeBackDepositorReward(
address from,
uint256 mintMPHAmount,
bool early
) external returns (uint256) {
uint256 takeBackAmount = early
? mintMPHAmount
: mintMPHAmount.decmul(
PRECISION.sub(poolDepositorRewardMultiplier[msg.sender])
);
if (takeBackAmount == 0) {
return 0;
}
mph.ownerTransfer(from, govTreasury, takeBackAmount);
return takeBackAmount;
}
function setGovTreasury(address newValue) external onlyOwner {
require(newValue != address(0), "MPHMinter: 0 address");
govTreasury = newValue;
emit ESetParamAddress(msg.sender, "govTreasury", newValue);
}
function setDevWallet(address newValue) external onlyOwner {
require(newValue != address(0), "MPHMinter: 0 address");
devWallet = newValue;
emit ESetParamAddress(msg.sender, "devWallet", newValue);
}
function setPoolMintingMultiplier(address pool, uint256 newMultiplier)
external
onlyOwner
{
require(pool.isContract(), "MPHMinter: pool not contract");
poolMintingMultiplier[pool] = newMultiplier;
emit ESetParamUint(msg.sender, "poolMintingMultiplier", newMultiplier);
}
function setPoolDepositorRewardMultiplier(
address pool,
uint256 newMultiplier
) external onlyOwner {
require(pool.isContract(), "MPHMinter: pool not contract");
require(newMultiplier <= PRECISION, "MPHMinter: invalid multiplier");
poolDepositorRewardMultiplier[pool] = newMultiplier;
emit ESetParamUint(
msg.sender,
"poolDepositorRewardMultiplier",
newMultiplier
);
}
function setPoolFunderRewardMultiplier(address pool, uint256 newMultiplier)
external
onlyOwner
{
require(pool.isContract(), "MPHMinter: pool not contract");
poolFunderRewardMultiplier[pool] = newMultiplier;
emit ESetParamUint(
msg.sender,
"poolFunderRewardMultiplier",
newMultiplier
);
}
}
文件 39 的 51:MPHToken.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";
import "@openzeppelin/contracts/ownership/Ownable.sol";
contract MPHToken is ERC20, ERC20Detailed, Ownable {
constructor() public ERC20Detailed("88mph.app", "MPH", 18) {}
function ownerMint(address account, uint256 amount)
public
onlyOwner
returns (bool)
{
_mint(account, amount);
return true;
}
function ownerTransfer(
address from,
address to,
uint256 amount
) public onlyOwner returns (bool) {
_transfer(from, to, amount);
return true;
}
}
文件 40 的 51:Math.sol
pragma solidity ^0.5.0;
library Math {
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
文件 41 的 51:NFT.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/token/ERC721/ERC721Metadata.sol";
import "@openzeppelin/contracts/ownership/Ownable.sol";
contract NFT is ERC721Metadata, Ownable {
string internal _contractURI;
constructor(string memory name, string memory symbol)
public
ERC721Metadata(name, symbol)
{}
function contractURI() external view returns (string memory) {
return _contractURI;
}
function mint(address to, uint256 tokenId) external onlyOwner {
_safeMint(to, tokenId);
}
function burn(uint256 tokenId) external onlyOwner {
_burn(tokenId);
}
function setContractURI(string calldata newURI) external onlyOwner {
_contractURI = newURI;
}
function setTokenURI(uint256 tokenId, string calldata newURI)
external
onlyOwner
{
_setTokenURI(tokenId, newURI);
}
function setBaseURI(string calldata newURI) external onlyOwner {
_setBaseURI(newURI);
}
}
文件 42 的 51:OneSplitAudit.sol
pragma solidity 0.5.17;
interface OneSplitAudit {
function swap(
address fromToken,
address destToken,
uint256 amount,
uint256 minReturn,
uint256[] calldata distribution,
uint256 flags
) external payable returns (uint256 returnAmount);
function getExpectedReturn(
address fromToken,
address destToken,
uint256 amount,
uint256 parts,
uint256 flags
)
external
view
returns (uint256 returnAmount, uint256[] memory distribution);
}
文件 43 的 51:Ownable.sol
pragma solidity ^0.5.0;
import "../GSN/Context.sol";
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(isOwner(), "Ownable: caller is not the owner");
_;
}
function isOwner() public view returns (bool) {
return _msgSender() == _owner;
}
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 44 的 51:PercentageFeeModel.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "./IFeeModel.sol";
contract PercentageFeeModel is IFeeModel {
using SafeMath for uint256;
address payable public beneficiary;
constructor(address payable _beneficiary) public {
beneficiary = _beneficiary;
}
function getFee(uint256 _txAmount)
external
pure
returns (uint256 _feeAmount)
{
_feeAmount = _txAmount.div(10);
}
}
文件 45 的 51:ReentrancyGuard.sol
pragma solidity ^0.5.0;
contract ReentrancyGuard {
bool private _notEntered;
constructor () internal {
_notEntered = true;
}
modifier nonReentrant() {
require(_notEntered, "ReentrancyGuard: reentrant call");
_notEntered = false;
_;
_notEntered = true;
}
}
文件 46 的 51:Rewards.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/ownership/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "./OneSplitAudit.sol";
contract IRewardDistributionRecipient is Ownable {
address rewardDistribution;
function notifyRewardAmount(uint256 reward) external;
modifier onlyRewardDistribution() {
require(
_msgSender() == rewardDistribution,
"Caller is not reward distribution"
);
_;
}
function setRewardDistribution(address _rewardDistribution)
external
onlyOwner
{
rewardDistribution = _rewardDistribution;
}
}
contract LPTokenWrapper {
using SafeMath for uint256;
using SafeERC20 for IERC20;
IERC20 public stakeToken;
uint256 private _totalSupply;
mapping(address => uint256) private _balances;
constructor(address _stakeToken) public {
stakeToken = IERC20(_stakeToken);
}
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function stake(uint256 amount) public {
_totalSupply = _totalSupply.add(amount);
_balances[msg.sender] = _balances[msg.sender].add(amount);
stakeToken.safeTransferFrom(msg.sender, address(this), amount);
}
function withdraw(uint256 amount) public {
_totalSupply = _totalSupply.sub(amount);
_balances[msg.sender] = _balances[msg.sender].sub(amount);
stakeToken.safeTransfer(msg.sender, amount);
}
}
contract Rewards is LPTokenWrapper, IRewardDistributionRecipient {
IERC20 public rewardToken;
OneSplitAudit public oneSplit;
uint256 public constant DURATION = 7 days;
uint256 public starttime;
uint256 public periodFinish = 0;
uint256 public rewardRate = 0;
uint256 public lastUpdateTime;
uint256 public rewardPerTokenStored;
bool public initialized = false;
mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public rewards;
event RewardAdded(uint256 reward);
event Staked(address indexed user, uint256 amount);
event Withdrawn(address indexed user, uint256 amount);
event RewardPaid(address indexed user, uint256 reward);
modifier updateReward(address account) {
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = lastTimeRewardApplicable();
if (account != address(0)) {
rewards[account] = earned(account);
userRewardPerTokenPaid[account] = rewardPerTokenStored;
}
_;
}
modifier checkStart {
require(block.timestamp >= starttime, "Rewards: not start");
_;
}
constructor(
address _stakeToken,
address _rewardToken,
address _oneSplit,
uint256 _starttime
) public LPTokenWrapper(_stakeToken) {
rewardToken = IERC20(_rewardToken);
oneSplit = OneSplitAudit(_oneSplit);
starttime = _starttime;
}
function lastTimeRewardApplicable() public view returns (uint256) {
return Math.min(block.timestamp, periodFinish);
}
function rewardPerToken() public view returns (uint256) {
if (totalSupply() == 0) {
return rewardPerTokenStored;
}
return
rewardPerTokenStored.add(
lastTimeRewardApplicable()
.sub(lastUpdateTime)
.mul(rewardRate)
.mul(1e18)
.div(totalSupply())
);
}
function earned(address account) public view returns (uint256) {
return
balanceOf(account)
.mul(rewardPerToken().sub(userRewardPerTokenPaid[account]))
.div(1e18)
.add(rewards[account]);
}
function stake(uint256 amount) public updateReward(msg.sender) checkStart {
require(amount > 0, "Rewards: cannot stake 0");
super.stake(amount);
emit Staked(msg.sender, amount);
}
function withdraw(uint256 amount)
public
updateReward(msg.sender)
checkStart
{
require(amount > 0, "Rewards: cannot withdraw 0");
super.withdraw(amount);
emit Withdrawn(msg.sender, amount);
}
function exit() external {
withdraw(balanceOf(msg.sender));
getReward();
}
function getReward() public updateReward(msg.sender) checkStart {
uint256 reward = earned(msg.sender);
if (reward > 0) {
rewards[msg.sender] = 0;
rewardToken.safeTransfer(msg.sender, reward);
emit RewardPaid(msg.sender, reward);
}
}
function notifyRewardAmount(uint256 reward)
external
onlyRewardDistribution
updateReward(address(0))
{
_notifyRewardAmount(reward);
}
function dump(address token, uint256 parts) external {
require(token != address(stakeToken), "Rewards: no dump stakeToken");
require(token != address(rewardToken), "Rewards: no dump rewardToken");
uint256 tokenBalance = IERC20(token).balanceOf(address(this));
(uint256 returnAmount, uint256[] memory distribution) = oneSplit
.getExpectedReturn(
token,
address(rewardToken),
tokenBalance,
parts,
0
);
uint256 receivedRewardTokenAmount = oneSplit.swap(
token,
address(rewardToken),
tokenBalance,
returnAmount,
distribution,
0
);
_notifyRewardAmount(receivedRewardTokenAmount);
}
function _notifyRewardAmount(uint256 reward) internal {
require(
reward < uint256(-1) / 10**18,
"Rewards: rewards too large, would lock"
);
if (block.timestamp > starttime) {
if (block.timestamp >= periodFinish) {
rewardRate = reward.div(DURATION);
} else {
uint256 remaining = periodFinish.sub(block.timestamp);
uint256 leftover = remaining.mul(rewardRate);
rewardRate = reward.add(leftover).div(DURATION);
}
lastUpdateTime = block.timestamp;
periodFinish = block.timestamp.add(DURATION);
emit RewardAdded(reward);
} else {
rewardRate = reward.div(DURATION);
lastUpdateTime = starttime;
periodFinish = starttime.add(DURATION);
emit RewardAdded(reward);
}
}
}
文件 47 的 51:SafeERC20.sol
pragma solidity ^0.5.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function callOptionalReturn(IERC20 token, bytes memory data) private {
require(address(token).isContract(), "SafeERC20: call to non-contract");
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 48 的 51:SafeMath.sol
pragma solidity ^0.5.0;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
文件 49 的 51:Vault.sol
pragma solidity 0.5.17;
interface Vault {
function deposit(uint256) external;
function withdraw(uint256) external;
function getPricePerFullShare() external view returns (uint256);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount)
external
returns (bool);
function allowance(address owner, address spender)
external
view
returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
文件 50 的 51:VaultMock.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../libs/DecMath.sol";
contract VaultMock is ERC20, ERC20Detailed {
using SafeMath for uint256;
using DecMath for uint256;
ERC20 public underlying;
constructor(address _underlying) public ERC20Detailed("yUSD", "yUSD", 18) {
underlying = ERC20(_underlying);
}
function deposit(uint256 tokenAmount) public {
uint256 sharePrice = getPricePerFullShare();
_mint(msg.sender, tokenAmount.decdiv(sharePrice));
underlying.transferFrom(msg.sender, address(this), tokenAmount);
}
function withdraw(uint256 sharesAmount) public {
uint256 sharePrice = getPricePerFullShare();
uint256 underlyingAmount = sharesAmount.decmul(sharePrice);
_burn(msg.sender, sharesAmount);
underlying.transfer(msg.sender, underlyingAmount);
}
function getPricePerFullShare() public view returns (uint256) {
uint256 _totalSupply = totalSupply();
if (_totalSupply == 0) {
return 10**18;
}
return underlying.balanceOf(address(this)).decdiv(_totalSupply);
}
}
文件 51 的 51:YVaultMarket.sol
pragma solidity 0.5.17;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/ownership/Ownable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "../IMoneyMarket.sol";
import "../../libs/DecMath.sol";
import "./imports/Vault.sol";
contract YVaultMarket is IMoneyMarket, Ownable {
using SafeMath for uint256;
using DecMath for uint256;
using SafeERC20 for ERC20;
using Address for address;
Vault public vault;
ERC20 public stablecoin;
constructor(address _vault, address _stablecoin) public {
require(
_vault != address(0) && _stablecoin != address(0),
"YVaultMarket: An input address is 0"
);
require(
_vault.isContract() && _stablecoin.isContract(),
"YVaultMarket: An input address is not a contract"
);
vault = Vault(_vault);
stablecoin = ERC20(_stablecoin);
}
function deposit(uint256 amount) external onlyOwner {
require(amount > 0, "YVaultMarket: amount is 0");
stablecoin.safeTransferFrom(msg.sender, address(this), amount);
stablecoin.safeIncreaseAllowance(address(vault), amount);
vault.deposit(amount);
}
function withdraw(uint256 amountInUnderlying)
external
onlyOwner
returns (uint256 actualAmountWithdrawn)
{
require(
amountInUnderlying > 0,
"YVaultMarket: amountInUnderlying is 0"
);
uint256 sharePrice = vault.getPricePerFullShare();
uint256 amountInShares = amountInUnderlying.decdiv(sharePrice);
vault.withdraw(amountInShares);
actualAmountWithdrawn = stablecoin.balanceOf(address(this));
stablecoin.safeTransfer(msg.sender, actualAmountWithdrawn);
}
function claimRewards() external {}
function totalValue() external returns (uint256) {
uint256 sharePrice = vault.getPricePerFullShare();
uint256 shareBalance = vault.balanceOf(address(this));
return shareBalance.decmul(sharePrice);
}
function incomeIndex() external returns (uint256) {
return vault.getPricePerFullShare();
}
function setRewards(address newValue) external {}
}
{
"compilationTarget": {
"contracts/DInterest.sol": "DInterest"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"components":[{"internalType":"uint256","name":"MinDepositPeriod","type":"uint256"},{"internalType":"uint256","name":"MaxDepositPeriod","type":"uint256"},{"internalType":"uint256","name":"MinDepositAmount","type":"uint256"},{"internalType":"uint256","name":"MaxDepositAmount","type":"uint256"}],"internalType":"struct DInterest.DepositLimit","name":"_depositLimit","type":"tuple"},{"internalType":"address","name":"_moneyMarket","type":"address"},{"internalType":"address","name":"_stablecoin","type":"address"},{"internalType":"address","name":"_feeModel","type":"address"},{"internalType":"address","name":"_interestModel","type":"address"},{"internalType":"address","name":"_interestOracle","type":"address"},{"internalType":"address","name":"_depositNFT","type":"address"},{"internalType":"address","name":"_fundingNFT","type":"address"},{"internalType":"address","name":"_mphMinter","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"depositID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maturationTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintMPHAmount","type":"uint256"}],"name":"EDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"fundingID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deficitAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintMPHAmount","type":"uint256"}],"name":"EFund","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"string","name":"paramName","type":"string"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"ESetParamAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"string","name":"paramName","type":"string"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"ESetParamUint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"depositID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"fundingID","type":"uint256"},{"indexed":false,"internalType":"bool","name":"early","type":"bool"},{"indexed":false,"internalType":"uint256","name":"takeBackMPHAmount","type":"uint256"}],"name":"EWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"constant":true,"inputs":[],"name":"MaxDepositAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MaxDepositPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MinDepositAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MinDepositPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"depositPeriodInSeconds","type":"uint256"}],"name":"calculateInterestAmount","outputs":[{"internalType":"uint256","name":"interestAmount","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"maturationTimestamp","type":"uint256"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"depositIsFunded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"depositNFT","outputs":[{"internalType":"contract NFT","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"depositsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"depositID","type":"uint256"},{"internalType":"uint256","name":"fundingID","type":"uint256"}],"name":"earlyWithdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"feeModel","outputs":[{"internalType":"contract IFeeModel","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"fundAll","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"toDepositID","type":"uint256"}],"name":"fundMultiple","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"fundingListLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"fundingNFT","outputs":[{"internalType":"contract NFT","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"depositID","type":"uint256"}],"name":"getDeposit","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"maturationTimestamp","type":"uint256"},{"internalType":"uint256","name":"interestOwed","type":"uint256"},{"internalType":"uint256","name":"initialMoneyMarketIncomeIndex","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"bool","name":"finalSurplusIsNegative","type":"bool"},{"internalType":"uint256","name":"finalSurplusAmount","type":"uint256"},{"internalType":"uint256","name":"mintMPHAmount","type":"uint256"}],"internalType":"struct DInterest.Deposit","name":"","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"fundingID","type":"uint256"}],"name":"getFunding","outputs":[{"components":[{"internalType":"uint256","name":"fromDepositID","type":"uint256"},{"internalType":"uint256","name":"toDepositID","type":"uint256"},{"internalType":"uint256","name":"recordedFundedDepositAmount","type":"uint256"},{"internalType":"uint256","name":"recordedMoneyMarketIncomeIndex","type":"uint256"}],"internalType":"struct DInterest.Funding","name":"","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"interestModel","outputs":[{"internalType":"contract IInterestModel","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"interestOracle","outputs":[{"internalType":"contract IInterestOracle","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"latestFundedDepositID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"moneyMarket","outputs":[{"internalType":"contract IMoneyMarket","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"moneyMarketIncomeIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"mphMinter","outputs":[{"internalType":"contract MPHMinter","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256[]","name":"amountList","type":"uint256[]"},{"internalType":"uint256[]","name":"maturationTimestampList","type":"uint256[]"}],"name":"multiDeposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256[]","name":"depositIDList","type":"uint256[]"},{"internalType":"uint256[]","name":"fundingIDList","type":"uint256[]"}],"name":"multiEarlyWithdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256[]","name":"depositIDList","type":"uint256[]"},{"internalType":"uint256[]","name":"fundingIDList","type":"uint256[]"}],"name":"multiWithdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"newURI","type":"string"}],"name":"setDepositNFTBaseURI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"newURI","type":"string"}],"name":"setDepositNFTContractURI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"newURI","type":"string"}],"name":"setDepositNFTTokenURI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newValue","type":"address"}],"name":"setFeeModel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"newURI","type":"string"}],"name":"setFundingNFTBaseURI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"newURI","type":"string"}],"name":"setFundingNFTContractURI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"newURI","type":"string"}],"name":"setFundingNFTTokenURI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newValue","type":"address"}],"name":"setInterestModel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newValue","type":"address"}],"name":"setInterestOracle","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"setMaxDepositAmount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"setMaxDepositPeriod","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"setMinDepositAmount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"setMinDepositPeriod","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newValue","type":"address"}],"name":"setRewards","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"stablecoin","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"surplus","outputs":[{"internalType":"bool","name":"isNegative","type":"bool"},{"internalType":"uint256","name":"surplusAmount","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"depositID","type":"uint256"}],"name":"surplusOfDeposit","outputs":[{"internalType":"bool","name":"isNegative","type":"bool"},{"internalType":"uint256","name":"surplusAmount","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalInterestOwed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"unfundedUserDepositAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"depositID","type":"uint256"},{"internalType":"uint256","name":"fundingID","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]