Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 926 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Rank Up | 16815360 | 686 days ago | IN | 0 ETH | 0.00545963 | ||||
Rank Up | 16738283 | 697 days ago | IN | 0 ETH | 0.00483057 | ||||
Rank Up | 15588372 | 858 days ago | IN | 0 ETH | 0.0007827 | ||||
Rank Up | 15142366 | 927 days ago | IN | 0 ETH | 0.00822316 | ||||
Rank Up | 14506138 | 1031 days ago | IN | 0 ETH | 0.0050337 | ||||
Rank Up | 14372651 | 1051 days ago | IN | 0 ETH | 0.00349642 | ||||
Rank Up | 14372602 | 1051 days ago | IN | 0 ETH | 0.0028866 | ||||
Rank Up | 14372548 | 1051 days ago | IN | 0 ETH | 0.00321579 | ||||
Rank Up | 14372512 | 1051 days ago | IN | 0 ETH | 0.00358816 | ||||
Rank Up | 14358323 | 1054 days ago | IN | 0 ETH | 0.00397075 | ||||
Rank Up | 14352074 | 1055 days ago | IN | 0 ETH | 0.00334106 | ||||
Rank Up | 14350936 | 1055 days ago | IN | 0 ETH | 0.00500116 | ||||
Rank Up | 14345553 | 1056 days ago | IN | 0 ETH | 0.0030488 | ||||
Rank Up | 14332614 | 1058 days ago | IN | 0 ETH | 0.00198197 | ||||
Rank Up | 14332416 | 1058 days ago | IN | 0 ETH | 0.00329977 | ||||
Rank Up | 14312815 | 1061 days ago | IN | 0 ETH | 0.00484791 | ||||
Rank Up | 14175321 | 1082 days ago | IN | 0 ETH | 0.01309413 | ||||
Rank Up | 14175314 | 1082 days ago | IN | 0 ETH | 0.01256632 | ||||
Rank Up | 14113172 | 1092 days ago | IN | 0 ETH | 0.00804944 | ||||
Rank Up | 14113160 | 1092 days ago | IN | 0 ETH | 0.00672815 | ||||
Rank Up | 14113054 | 1092 days ago | IN | 0 ETH | 0.00846526 | ||||
Rank Up | 13907645 | 1123 days ago | IN | 0 ETH | 0.01039605 | ||||
Rank Up | 13907099 | 1123 days ago | IN | 0 ETH | 0.0103861 | ||||
Rank Up | 13853473 | 1132 days ago | IN | 0 ETH | 0.00577057 | ||||
Rank Up | 13840199 | 1134 days ago | IN | 0 ETH | 0.00558943 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
PeakReward
Compiler Version
v0.5.17+commit.d19bba13
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity 0.5.17; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/access/roles/SignerRole.sol"; import "../staking/PeakStaking.sol"; import "../PeakToken.sol"; import "../IUniswapOracle.sol"; contract PeakReward is SignerRole { using SafeMath for uint256; using SafeERC20 for IERC20; event Register(address user, address referrer); event RankChange(address user, uint256 oldRank, uint256 newRank); event PayCommission( address referrer, address recipient, address token, uint256 amount, uint8 level ); event ChangedCareerValue(address user, uint256 changeAmount, bool positive); event ReceiveRankReward(address user, uint256 peakReward); modifier regUser(address user) { if (!isUser[user]) { isUser[user] = true; emit Register(user, address(0)); } _; } uint256 public constant PEAK_MINT_CAP = 5 * 10**15; // 50 million PEAK uint256 internal constant COMMISSION_RATE = 20 * (10**16); // 20% uint256 internal constant PEAK_PRECISION = 10**8; uint256 internal constant USDC_PRECISION = 10**6; uint8 internal constant COMMISSION_LEVELS = 8; mapping(address => address) public referrerOf; mapping(address => bool) public isUser; mapping(address => uint256) public careerValue; // AKA DSV mapping(address => uint256) public rankOf; mapping(uint256 => mapping(uint256 => uint256)) public rankReward; // (beforeRank, afterRank) => rewardInPeak mapping(address => mapping(uint256 => uint256)) public downlineRanks; // (referrer, rank) => numReferredUsersWithRank uint256[] public commissionPercentages; uint256[] public commissionStakeRequirements; uint256 public mintedPeakTokens; address public marketPeakWallet; PeakStaking public peakStaking; PeakToken public peakToken; address public stablecoin; IUniswapOracle public oracle; constructor( address _marketPeakWallet, address _peakStaking, address _peakToken, address _stablecoin, address _oracle ) public { // initialize commission percentages for each level commissionPercentages.push(10 * (10**16)); // 10% commissionPercentages.push(4 * (10**16)); // 4% commissionPercentages.push(2 * (10**16)); // 2% commissionPercentages.push(1 * (10**16)); // 1% commissionPercentages.push(1 * (10**16)); // 1% commissionPercentages.push(1 * (10**16)); // 1% commissionPercentages.push(5 * (10**15)); // 0.5% commissionPercentages.push(5 * (10**15)); // 0.5% // initialize commission stake requirements for each level commissionStakeRequirements.push(0); commissionStakeRequirements.push(PEAK_PRECISION.mul(2000)); commissionStakeRequirements.push(PEAK_PRECISION.mul(4000)); commissionStakeRequirements.push(PEAK_PRECISION.mul(6000)); commissionStakeRequirements.push(PEAK_PRECISION.mul(7000)); commissionStakeRequirements.push(PEAK_PRECISION.mul(8000)); commissionStakeRequirements.push(PEAK_PRECISION.mul(9000)); commissionStakeRequirements.push(PEAK_PRECISION.mul(10000)); // initialize rank rewards for (uint256 i = 0; i < 8; i = i.add(1)) { uint256 rewardInUSDC = 0; for (uint256 j = i.add(1); j <= 8; j = j.add(1)) { if (j == 1) { rewardInUSDC = rewardInUSDC.add(USDC_PRECISION.mul(100)); } else if (j == 2) { rewardInUSDC = rewardInUSDC.add(USDC_PRECISION.mul(300)); } else if (j == 3) { rewardInUSDC = rewardInUSDC.add(USDC_PRECISION.mul(600)); } else if (j == 4) { rewardInUSDC = rewardInUSDC.add(USDC_PRECISION.mul(1200)); } else if (j == 5) { rewardInUSDC = rewardInUSDC.add(USDC_PRECISION.mul(2400)); } else if (j == 6) { rewardInUSDC = rewardInUSDC.add(USDC_PRECISION.mul(7500)); } else if (j == 7) { rewardInUSDC = rewardInUSDC.add(USDC_PRECISION.mul(15000)); } else { rewardInUSDC = rewardInUSDC.add(USDC_PRECISION.mul(50000)); } rankReward[i][j] = rewardInUSDC; } } marketPeakWallet = _marketPeakWallet; peakStaking = PeakStaking(_peakStaking); peakToken = PeakToken(_peakToken); stablecoin = _stablecoin; oracle = IUniswapOracle(_oracle); } /** @notice Registers a group of referrals relationship. @param users The array of users @param referrers The group of referrers of `users` */ function multiRefer(address[] calldata users, address[] calldata referrers) external onlySigner { require(users.length == referrers.length, "PeakReward: arrays length are not equal"); for (uint256 i = 0; i < users.length; i++) { refer(users[i], referrers[i]); } } /** @notice Registers a referral relationship @param user The user who is being referred @param referrer The referrer of `user` */ function refer(address user, address referrer) public onlySigner { require(!isUser[user], "PeakReward: referred is already a user"); require(user != referrer, "PeakReward: can't refer self"); require( user != address(0) && referrer != address(0), "PeakReward: 0 address" ); isUser[user] = true; isUser[referrer] = true; referrerOf[user] = referrer; downlineRanks[referrer][0] = downlineRanks[referrer][0].add(1); emit Register(user, referrer); } function canRefer(address user, address referrer) public view returns (bool) { return !isUser[user] && user != referrer && user != address(0) && referrer != address(0); } /** @notice Distributes commissions to a referrer and their referrers @param referrer The referrer who will receive commission @param commissionToken The ERC20 token that the commission is paid in @param rawCommission The raw commission that will be distributed amongst referrers @param returnLeftovers If true, leftover commission is returned to the sender. If false, leftovers will be paid to MarketPeak. */ function payCommission( address referrer, address commissionToken, uint256 rawCommission, bool returnLeftovers ) public regUser(referrer) onlySigner returns (uint256 leftoverAmount) { // transfer the raw commission from `msg.sender` IERC20 token = IERC20(commissionToken); token.safeTransferFrom(msg.sender, address(this), rawCommission); // payout commissions to referrers of different levels address ptr = referrer; uint256 commissionLeft = rawCommission; uint8 i = 0; while (ptr != address(0) && i < COMMISSION_LEVELS) { if (_peakStakeOf(ptr) >= commissionStakeRequirements[i]) { // referrer has enough stake, give commission uint256 com = rawCommission.mul(commissionPercentages[i]).div( COMMISSION_RATE ); if (com > commissionLeft) { com = commissionLeft; } token.safeTransfer(ptr, com); commissionLeft = commissionLeft.sub(com); if (commissionToken == address(peakToken)) { incrementCareerValueInPeak(ptr, com); } else if (commissionToken == stablecoin) { incrementCareerValueInUsdc(ptr, com); } emit PayCommission(referrer, ptr, commissionToken, com, i); } ptr = referrerOf[ptr]; i += 1; } // handle leftovers if (returnLeftovers) { // return leftovers to `msg.sender` token.safeTransfer(msg.sender, commissionLeft); return commissionLeft; } else { // give leftovers to MarketPeak wallet token.safeTransfer(marketPeakWallet, commissionLeft); return 0; } } /** @notice Increments a user's career value @param user The user @param incCV The CV increase amount, in Usdc */ function incrementCareerValueInUsdc(address user, uint256 incCV) public regUser(user) onlySigner { careerValue[user] = careerValue[user].add(incCV); emit ChangedCareerValue(user, incCV, true); } /** @notice Increments a user's career value @param user The user @param incCVInPeak The CV increase amount, in PEAK tokens */ function incrementCareerValueInPeak(address user, uint256 incCVInPeak) public regUser(user) onlySigner { uint256 peakPriceInUsdc = _getPeakPriceInUsdc(); uint256 incCVInUsdc = incCVInPeak.mul(peakPriceInUsdc).div( PEAK_PRECISION ); careerValue[user] = careerValue[user].add(incCVInUsdc); emit ChangedCareerValue(user, incCVInUsdc, true); } /** @notice Returns a user's rank in the PeakDeFi system based only on career value @param user The user whose rank will be queried */ function cvRankOf(address user) public view returns (uint256) { uint256 cv = careerValue[user]; if (cv < USDC_PRECISION.mul(100)) { return 0; } else if (cv < USDC_PRECISION.mul(250)) { return 1; } else if (cv < USDC_PRECISION.mul(750)) { return 2; } else if (cv < USDC_PRECISION.mul(1500)) { return 3; } else if (cv < USDC_PRECISION.mul(3000)) { return 4; } else if (cv < USDC_PRECISION.mul(10000)) { return 5; } else if (cv < USDC_PRECISION.mul(50000)) { return 6; } else if (cv < USDC_PRECISION.mul(150000)) { return 7; } else { return 8; } } function rankUp(address user) external { // verify rank up conditions uint256 currentRank = rankOf[user]; uint256 cvRank = cvRankOf(user); require(cvRank > currentRank, "PeakReward: career value is not enough!"); require(downlineRanks[user][currentRank] >= 2 || currentRank == 0, "PeakReward: downlines count and requirement not passed!"); // Target rank always should be +1 rank from current rank uint256 targetRank = currentRank + 1; // increase user rank rankOf[user] = targetRank; emit RankChange(user, currentRank, targetRank); address referrer = referrerOf[user]; if (referrer != address(0)) { downlineRanks[referrer][targetRank] = downlineRanks[referrer][targetRank] .add(1); downlineRanks[referrer][currentRank] = downlineRanks[referrer][currentRank] .sub(1); } // give user rank reward uint256 rewardInPeak = rankReward[currentRank][targetRank] .mul(PEAK_PRECISION) .div(_getPeakPriceInUsdc()); if (mintedPeakTokens.add(rewardInPeak) <= PEAK_MINT_CAP) { // mint if under cap, do nothing if over cap mintedPeakTokens = mintedPeakTokens.add(rewardInPeak); peakToken.mint(user, rewardInPeak); emit ReceiveRankReward(user, rewardInPeak); } } function canRankUp(address user) external view returns (bool) { uint256 currentRank = rankOf[user]; uint256 cvRank = cvRankOf(user); return (cvRank > currentRank) && (downlineRanks[user][currentRank] >= 2 || currentRank == 0); } /** @notice Returns a user's current staked PEAK amount, scaled by `PEAK_PRECISION`. @param user The user whose stake will be queried */ function _peakStakeOf(address user) internal view returns (uint256) { return peakStaking.userStakeAmount(user); } /** @notice Returns the price of PEAK token in Usdc, scaled by `USDC_PRECISION`. */ function _getPeakPriceInUsdc() internal returns (uint256) { oracle.update(); uint256 priceInUSDC = oracle.consult(address(peakToken), PEAK_PRECISION); if (priceInUSDC == 0) { return USDC_PRECISION.mul(3).div(10); } return priceInUSDC; } }
pragma solidity 0.5.17; import "@openzeppelin/contracts/ownership/Ownable.sol"; import "../interfaces/Comptroller.sol"; import "../interfaces/PriceOracle.sol"; import "../interfaces/CERC20.sol"; import "../interfaces/CEther.sol"; import "../Utils.sol"; contract CompoundOrder is Utils(address(0), address(0), address(0)), Ownable { // Constants uint256 internal constant NEGLIGIBLE_DEBT = 100; // we don't care about debts below 10^-4 USDC (0.1 cent) uint256 internal constant MAX_REPAY_STEPS = 3; // Max number of times we attempt to repay remaining debt uint256 internal constant DEFAULT_LIQUIDITY_SLIPPAGE = 10 ** 12; // 1e-6 slippage for redeeming liquidity when selling order uint256 internal constant FALLBACK_LIQUIDITY_SLIPPAGE = 10 ** 15; // 0.1% slippage for redeeming liquidity when selling order uint256 internal constant MAX_LIQUIDITY_SLIPPAGE = 10 ** 17; // 10% max slippage for redeeming liquidity when selling order // Contract instances Comptroller public COMPTROLLER; // The Compound comptroller PriceOracle public ORACLE; // The Compound price oracle CERC20 public CUSDC; // The Compound USDC market token address public CETH_ADDR; // Instance variables uint256 public stake; uint256 public collateralAmountInUSDC; uint256 public loanAmountInUSDC; uint256 public cycleNumber; uint256 public buyTime; // Timestamp for order execution uint256 public outputAmount; // Records the total output USDC after order is sold address public compoundTokenAddr; bool public isSold; bool public orderType; // True for shorting, false for longing bool internal initialized; constructor() public {} function init( address _compoundTokenAddr, uint256 _cycleNumber, uint256 _stake, uint256 _collateralAmountInUSDC, uint256 _loanAmountInUSDC, bool _orderType, address _usdcAddr, address payable _kyberAddr, address _comptrollerAddr, address _priceOracleAddr, address _cUSDCAddr, address _cETHAddr ) public { require(!initialized); initialized = true; // Initialize details of order require(_compoundTokenAddr != _cUSDCAddr); require(_stake > 0 && _collateralAmountInUSDC > 0 && _loanAmountInUSDC > 0); // Validate inputs stake = _stake; collateralAmountInUSDC = _collateralAmountInUSDC; loanAmountInUSDC = _loanAmountInUSDC; cycleNumber = _cycleNumber; compoundTokenAddr = _compoundTokenAddr; orderType = _orderType; COMPTROLLER = Comptroller(_comptrollerAddr); ORACLE = PriceOracle(_priceOracleAddr); CUSDC = CERC20(_cUSDCAddr); CETH_ADDR = _cETHAddr; USDC_ADDR = _usdcAddr; KYBER_ADDR = _kyberAddr; usdc = ERC20Detailed(_usdcAddr); kyber = KyberNetwork(_kyberAddr); // transfer ownership to msg.sender _transferOwnership(msg.sender); } /** * @notice Executes the Compound order * @param _minPrice the minimum token price * @param _maxPrice the maximum token price */ function executeOrder(uint256 _minPrice, uint256 _maxPrice) public; /** * @notice Sells the Compound order and returns assets to PeakDeFiFund * @param _minPrice the minimum token price * @param _maxPrice the maximum token price */ function sellOrder(uint256 _minPrice, uint256 _maxPrice) public returns (uint256 _inputAmount, uint256 _outputAmount); /** * @notice Repays the loans taken out to prevent the collateral ratio from dropping below threshold * @param _repayAmountInUSDC the amount to repay, in USDC */ function repayLoan(uint256 _repayAmountInUSDC) public; /** * @notice Emergency method, which allow to transfer selected tokens to the fund address * @param _tokenAddr address of withdrawn token * @param _receiver address who should receive tokens */ function emergencyExitTokens(address _tokenAddr, address _receiver) public onlyOwner { ERC20Detailed token = ERC20Detailed(_tokenAddr); token.safeTransfer(_receiver, token.balanceOf(address(this))); } function getMarketCollateralFactor() public view returns (uint256); function getCurrentCollateralInUSDC() public returns (uint256 _amount); function getCurrentBorrowInUSDC() public returns (uint256 _amount); function getCurrentCashInUSDC() public view returns (uint256 _amount); /** * @notice Calculates the current profit in USDC * @return the profit amount */ function getCurrentProfitInUSDC() public returns (bool _isNegative, uint256 _amount) { uint256 l; uint256 r; if (isSold) { l = outputAmount; r = collateralAmountInUSDC; } else { uint256 cash = getCurrentCashInUSDC(); uint256 supply = getCurrentCollateralInUSDC(); uint256 borrow = getCurrentBorrowInUSDC(); if (cash >= borrow) { l = supply.add(cash); r = borrow.add(collateralAmountInUSDC); } else { l = supply; r = borrow.sub(cash).mul(PRECISION).div(getMarketCollateralFactor()).add(collateralAmountInUSDC); } } if (l >= r) { return (false, l.sub(r)); } else { return (true, r.sub(l)); } } /** * @notice Calculates the current collateral ratio on Compound, using 18 decimals * @return the collateral ratio */ function getCurrentCollateralRatioInUSDC() public returns (uint256 _amount) { uint256 supply = getCurrentCollateralInUSDC(); uint256 borrow = getCurrentBorrowInUSDC(); if (borrow == 0) { return uint256(-1); } return supply.mul(PRECISION).div(borrow); } /** * @notice Calculates the current liquidity (supply - collateral) on the Compound platform * @return the liquidity */ function getCurrentLiquidityInUSDC() public returns (bool _isNegative, uint256 _amount) { uint256 supply = getCurrentCollateralInUSDC(); uint256 borrow = getCurrentBorrowInUSDC().mul(PRECISION).div(getMarketCollateralFactor()); if (supply >= borrow) { return (false, supply.sub(borrow)); } else { return (true, borrow.sub(supply)); } } function __sellUSDCForToken(uint256 _usdcAmount) internal returns (uint256 _actualUSDCAmount, uint256 _actualTokenAmount) { ERC20Detailed t = __underlyingToken(compoundTokenAddr); (,, _actualTokenAmount, _actualUSDCAmount) = __kyberTrade(usdc, _usdcAmount, t); // Sell USDC for tokens on Kyber require(_actualUSDCAmount > 0 && _actualTokenAmount > 0); // Validate return values } function __sellTokenForUSDC(uint256 _tokenAmount) internal returns (uint256 _actualUSDCAmount, uint256 _actualTokenAmount) { ERC20Detailed t = __underlyingToken(compoundTokenAddr); (,, _actualUSDCAmount, _actualTokenAmount) = __kyberTrade(t, _tokenAmount, usdc); // Sell tokens for USDC on Kyber require(_actualUSDCAmount > 0 && _actualTokenAmount > 0); // Validate return values } // Convert a USDC amount to the amount of a given token that's of equal value function __usdcToToken(address _cToken, uint256 _usdcAmount) internal view returns (uint256) { ERC20Detailed t = __underlyingToken(_cToken); return _usdcAmount.mul(PRECISION).div(10 ** getDecimals(usdc)).mul(10 ** getDecimals(t)).div(ORACLE.getUnderlyingPrice(_cToken).mul(10 ** getDecimals(t)).div(PRECISION)); } // Convert a compound token amount to the amount of USDC that's of equal value function __tokenToUSDC(address _cToken, uint256 _tokenAmount) internal view returns (uint256) { return _tokenAmount.mul(ORACLE.getUnderlyingPrice(_cToken)).div(PRECISION).mul(10 ** getDecimals(usdc)).div(PRECISION); } function __underlyingToken(address _cToken) internal view returns (ERC20Detailed) { if (_cToken == CETH_ADDR) { // ETH return ETH_TOKEN_ADDRESS; } CERC20 ct = CERC20(_cToken); address underlyingToken = ct.underlying(); ERC20Detailed t = ERC20Detailed(underlyingToken); return t; } function() external payable {} }
pragma solidity ^0.5.0; import "../GSN/Context.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. * * 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 Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { 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(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _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 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 onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
pragma solidity ^0.5.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. */ contract Context { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
pragma solidity 0.5.17; // Compound finance comptroller interface Comptroller { function enterMarkets(address[] calldata cTokens) external returns (uint[] memory); function markets(address cToken) external view returns (bool isListed, uint256 collateralFactorMantissa); }
pragma solidity 0.5.17; // Compound finance's price oracle interface PriceOracle { // returns the price of the underlying token in USD, scaled by 10**(36 - underlyingPrecision) function getUnderlyingPrice(address cToken) external view returns (uint); }
pragma solidity 0.5.17; // Compound finance ERC20 market interface interface CERC20 { function mint(uint mintAmount) external returns (uint); function redeemUnderlying(uint redeemAmount) external returns (uint); function borrow(uint borrowAmount) external returns (uint); function repayBorrow(uint repayAmount) external returns (uint); function borrowBalanceCurrent(address account) external returns (uint); function exchangeRateCurrent() external returns (uint); function balanceOf(address account) external view returns (uint); function decimals() external view returns (uint); function underlying() external view returns (address); }
pragma solidity 0.5.17; // Compound finance Ether market interface interface CEther { function mint() external payable; function redeemUnderlying(uint redeemAmount) external returns (uint); function borrow(uint borrowAmount) external returns (uint); function repayBorrow() external payable; function borrowBalanceCurrent(address account) external returns (uint); function exchangeRateCurrent() external returns (uint); function balanceOf(address account) external view returns (uint); function decimals() external view returns (uint); }
pragma solidity 0.5.17; import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "./interfaces/KyberNetwork.sol"; import "./interfaces/OneInchExchange.sol"; /** * @title The smart contract for useful utility functions and constants. * @author Zefram Lou (Zebang Liu) */ contract Utils { using SafeMath for uint256; using SafeERC20 for ERC20Detailed; /** * @notice Checks if `_token` is a valid token. * @param _token the token's address */ modifier isValidToken(address _token) { require(_token != address(0)); if (_token != address(ETH_TOKEN_ADDRESS)) { require(isContract(_token)); } _; } address public USDC_ADDR; address payable public KYBER_ADDR; address payable public ONEINCH_ADDR; bytes public constant PERM_HINT = "PERM"; // The address Kyber Network uses to represent Ether ERC20Detailed internal constant ETH_TOKEN_ADDRESS = ERC20Detailed(0x00eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee); ERC20Detailed internal usdc; KyberNetwork internal kyber; uint256 constant internal PRECISION = (10**18); uint256 constant internal MAX_QTY = (10**28); // 10B tokens uint256 constant internal ETH_DECIMALS = 18; uint256 constant internal MAX_DECIMALS = 18; constructor( address _usdcAddr, address payable _kyberAddr, address payable _oneInchAddr ) public { USDC_ADDR = _usdcAddr; KYBER_ADDR = _kyberAddr; ONEINCH_ADDR = _oneInchAddr; usdc = ERC20Detailed(_usdcAddr); kyber = KyberNetwork(_kyberAddr); } /** * @notice Get the number of decimals of a token * @param _token the token to be queried * @return number of decimals */ function getDecimals(ERC20Detailed _token) internal view returns(uint256) { if (address(_token) == address(ETH_TOKEN_ADDRESS)) { return uint256(ETH_DECIMALS); } return uint256(_token.decimals()); } /** * @notice Get the token balance of an account * @param _token the token to be queried * @param _addr the account whose balance will be returned * @return token balance of the account */ function getBalance(ERC20Detailed _token, address _addr) internal view returns(uint256) { if (address(_token) == address(ETH_TOKEN_ADDRESS)) { return uint256(_addr.balance); } return uint256(_token.balanceOf(_addr)); } /** * @notice Calculates the rate of a trade. The rate is the price of the source token in the dest token, in 18 decimals. * Note: the rate is on the token level, not the wei level, so for example if 1 Atoken = 10 Btoken, then the rate * from A to B is 10 * 10**18, regardless of how many decimals each token uses. * @param srcAmount amount of source token * @param destAmount amount of dest token * @param srcDecimals decimals used by source token * @param dstDecimals decimals used by dest token */ function calcRateFromQty(uint256 srcAmount, uint256 destAmount, uint256 srcDecimals, uint256 dstDecimals) internal pure returns(uint) { require(srcAmount <= MAX_QTY); require(destAmount <= MAX_QTY); if (dstDecimals >= srcDecimals) { require((dstDecimals - srcDecimals) <= MAX_DECIMALS); return (destAmount * PRECISION / ((10 ** (dstDecimals - srcDecimals)) * srcAmount)); } else { require((srcDecimals - dstDecimals) <= MAX_DECIMALS); return (destAmount * PRECISION * (10 ** (srcDecimals - dstDecimals)) / srcAmount); } } /** * @notice Wrapper function for doing token conversion on Kyber Network * @param _srcToken the token to convert from * @param _srcAmount the amount of tokens to be converted * @param _destToken the destination token * @return _destPriceInSrc the price of the dest token, in terms of source tokens * _srcPriceInDest the price of the source token, in terms of dest tokens * _actualDestAmount actual amount of dest token traded * _actualSrcAmount actual amount of src token traded */ function __kyberTrade(ERC20Detailed _srcToken, uint256 _srcAmount, ERC20Detailed _destToken) internal returns( uint256 _destPriceInSrc, uint256 _srcPriceInDest, uint256 _actualDestAmount, uint256 _actualSrcAmount ) { require(_srcToken != _destToken); uint256 beforeSrcBalance = getBalance(_srcToken, address(this)); uint256 msgValue; if (_srcToken != ETH_TOKEN_ADDRESS) { msgValue = 0; _srcToken.safeApprove(KYBER_ADDR, 0); _srcToken.safeApprove(KYBER_ADDR, _srcAmount); } else { msgValue = _srcAmount; } _actualDestAmount = kyber.tradeWithHint.value(msgValue)( _srcToken, _srcAmount, _destToken, toPayableAddr(address(this)), MAX_QTY, 1, address(0), PERM_HINT ); _actualSrcAmount = beforeSrcBalance.sub(getBalance(_srcToken, address(this))); require(_actualDestAmount > 0 && _actualSrcAmount > 0); _destPriceInSrc = calcRateFromQty(_actualDestAmount, _actualSrcAmount, getDecimals(_destToken), getDecimals(_srcToken)); _srcPriceInDest = calcRateFromQty(_actualSrcAmount, _actualDestAmount, getDecimals(_srcToken), getDecimals(_destToken)); } /** * @notice Wrapper function for doing token conversion on 1inch * @param _srcToken the token to convert from * @param _srcAmount the amount of tokens to be converted * @param _destToken the destination token * @return _destPriceInSrc the price of the dest token, in terms of source tokens * _srcPriceInDest the price of the source token, in terms of dest tokens * _actualDestAmount actual amount of dest token traded * _actualSrcAmount actual amount of src token traded */ function __oneInchTrade(ERC20Detailed _srcToken, uint256 _srcAmount, ERC20Detailed _destToken, bytes memory _calldata) internal returns( uint256 _destPriceInSrc, uint256 _srcPriceInDest, uint256 _actualDestAmount, uint256 _actualSrcAmount ) { require(_srcToken != _destToken); uint256 beforeSrcBalance = getBalance(_srcToken, address(this)); uint256 beforeDestBalance = getBalance(_destToken, address(this)); // Note: _actualSrcAmount is being used as msgValue here, because otherwise we'd run into the stack too deep error if (_srcToken != ETH_TOKEN_ADDRESS) { _actualSrcAmount = 0; OneInchExchange dex = OneInchExchange(ONEINCH_ADDR); address approvalHandler = dex.spender(); _srcToken.safeApprove(approvalHandler, 0); _srcToken.safeApprove(approvalHandler, _srcAmount); } else { _actualSrcAmount = _srcAmount; } // trade through 1inch proxy (bool success,) = ONEINCH_ADDR.call.value(_actualSrcAmount)(_calldata); require(success); // calculate trade amounts and price _actualDestAmount = getBalance(_destToken, address(this)).sub(beforeDestBalance); _actualSrcAmount = beforeSrcBalance.sub(getBalance(_srcToken, address(this))); require(_actualDestAmount > 0 && _actualSrcAmount > 0); _destPriceInSrc = calcRateFromQty(_actualDestAmount, _actualSrcAmount, getDecimals(_destToken), getDecimals(_srcToken)); _srcPriceInDest = calcRateFromQty(_actualSrcAmount, _actualDestAmount, getDecimals(_srcToken), getDecimals(_destToken)); } /** * @notice Checks if an Ethereum account is a smart contract * @param _addr the account to be checked * @return True if the account is a smart contract, false otherwise */ function isContract(address _addr) internal view returns(bool) { uint256 size; if (_addr == address(0)) return false; assembly { size := extcodesize(_addr) } return size>0; } function toPayableAddr(address _addr) internal pure returns (address payable) { return address(uint160(_addr)); } }
pragma solidity ^0.5.0; import "./IERC20.sol"; /** * @dev Optional functions from the ERC20 standard. */ contract ERC20Detailed is IERC20 { string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of * these values are immutable: they can only be set once during * construction. */ constructor (string memory name, string memory symbol, uint8 decimals) public { _name = name; _symbol = symbol; _decimals = decimals; } /** * @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; } /** * @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. * * 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; } }
pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ 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); }
pragma solidity ^0.5.0; import "./IERC20.sol"; import "../../math/SafeMath.sol"; import "../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ 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 { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length 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)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. // A Solidity high level call has three parts: // 1. The target address is checked to verify it contains contract code // 2. The call itself is made, and success asserted // 3. The return value is decoded, which in turn checks the size of the returned data. // solhint-disable-next-line max-line-length require(address(token).isContract(), "SafeERC20: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
pragma solidity ^0.5.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. * * _Available since v2.4.0._ */ 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. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 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. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
pragma solidity ^0.5.5; /** * @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) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @dev Converts an `address` into `address payable`. Note that this is * simply a type cast: the actual underlying value is not changed. * * _Available since v2.4.0._ */ function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } /** * @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]. * * _Available since v2.4.0._ */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-call-value (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } }
pragma solidity 0.5.17; import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; /** * @title The interface for the Kyber Network smart contract * @author Zefram Lou (Zebang Liu) */ interface KyberNetwork { function getExpectedRate(ERC20Detailed src, ERC20Detailed dest, uint srcQty) external view returns (uint expectedRate, uint slippageRate); function tradeWithHint( ERC20Detailed src, uint srcAmount, ERC20Detailed dest, address payable destAddress, uint maxDestAmount, uint minConversionRate, address walletId, bytes calldata hint) external payable returns(uint); }
pragma solidity 0.5.17; interface OneInchExchange { function spender() external view returns (address); }
pragma solidity 0.5.17; import "./LongCERC20Order.sol"; import "./LongCEtherOrder.sol"; import "./ShortCERC20Order.sol"; import "./ShortCEtherOrder.sol"; import "../lib/CloneFactory.sol"; contract CompoundOrderFactory is CloneFactory { address public SHORT_CERC20_LOGIC_CONTRACT; address public SHORT_CEther_LOGIC_CONTRACT; address public LONG_CERC20_LOGIC_CONTRACT; address public LONG_CEther_LOGIC_CONTRACT; address public USDC_ADDR; address payable public KYBER_ADDR; address public COMPTROLLER_ADDR; address public ORACLE_ADDR; address public CUSDC_ADDR; address public CETH_ADDR; constructor( address _shortCERC20LogicContract, address _shortCEtherLogicContract, address _longCERC20LogicContract, address _longCEtherLogicContract, address _usdcAddr, address payable _kyberAddr, address _comptrollerAddr, address _priceOracleAddr, address _cUSDCAddr, address _cETHAddr ) public { SHORT_CERC20_LOGIC_CONTRACT = _shortCERC20LogicContract; SHORT_CEther_LOGIC_CONTRACT = _shortCEtherLogicContract; LONG_CERC20_LOGIC_CONTRACT = _longCERC20LogicContract; LONG_CEther_LOGIC_CONTRACT = _longCEtherLogicContract; USDC_ADDR = _usdcAddr; KYBER_ADDR = _kyberAddr; COMPTROLLER_ADDR = _comptrollerAddr; ORACLE_ADDR = _priceOracleAddr; CUSDC_ADDR = _cUSDCAddr; CETH_ADDR = _cETHAddr; } function createOrder( address _compoundTokenAddr, uint256 _cycleNumber, uint256 _stake, uint256 _collateralAmountInUSDC, uint256 _loanAmountInUSDC, bool _orderType ) external returns (CompoundOrder) { require(_compoundTokenAddr != address(0)); CompoundOrder order; address payable clone; if (_compoundTokenAddr != CETH_ADDR) { if (_orderType) { // Short CERC20 Order clone = toPayableAddr(createClone(SHORT_CERC20_LOGIC_CONTRACT)); } else { // Long CERC20 Order clone = toPayableAddr(createClone(LONG_CERC20_LOGIC_CONTRACT)); } } else { if (_orderType) { // Short CEther Order clone = toPayableAddr(createClone(SHORT_CEther_LOGIC_CONTRACT)); } else { // Long CEther Order clone = toPayableAddr(createClone(LONG_CEther_LOGIC_CONTRACT)); } } order = CompoundOrder(clone); order.init(_compoundTokenAddr, _cycleNumber, _stake, _collateralAmountInUSDC, _loanAmountInUSDC, _orderType, USDC_ADDR, KYBER_ADDR, COMPTROLLER_ADDR, ORACLE_ADDR, CUSDC_ADDR, CETH_ADDR); order.transferOwnership(msg.sender); return order; } function getMarketCollateralFactor(address _compoundTokenAddr) external view returns (uint256) { Comptroller troll = Comptroller(COMPTROLLER_ADDR); (, uint256 factor) = troll.markets(_compoundTokenAddr); return factor; } function tokenIsListed(address _compoundTokenAddr) external view returns (bool) { Comptroller troll = Comptroller(COMPTROLLER_ADDR); (bool isListed,) = troll.markets(_compoundTokenAddr); return isListed; } function toPayableAddr(address _addr) internal pure returns (address payable) { return address(uint160(_addr)); } }
pragma solidity 0.5.17; import "./CompoundOrder.sol"; contract LongCERC20Order is CompoundOrder { modifier isValidPrice(uint256 _minPrice, uint256 _maxPrice) { // Ensure token's price is between _minPrice and _maxPrice uint256 tokenPrice = ORACLE.getUnderlyingPrice(compoundTokenAddr); // Get the longing token's price in USD require(tokenPrice > 0); // Ensure asset exists on Compound require(tokenPrice >= _minPrice && tokenPrice <= _maxPrice); // Ensure price is within range _; } function executeOrder(uint256 _minPrice, uint256 _maxPrice) public onlyOwner isValidToken(compoundTokenAddr) isValidPrice(_minPrice, _maxPrice) { buyTime = now; // Get funds in USDC from PeakDeFiFund usdc.safeTransferFrom(owner(), address(this), collateralAmountInUSDC); // Transfer USDC from PeakDeFiFund // Convert received USDC to longing token (,uint256 actualTokenAmount) = __sellUSDCForToken(collateralAmountInUSDC); // Enter Compound markets CERC20 market = CERC20(compoundTokenAddr); address[] memory markets = new address[](2); markets[0] = compoundTokenAddr; markets[1] = address(CUSDC); uint[] memory errors = COMPTROLLER.enterMarkets(markets); require(errors[0] == 0 && errors[1] == 0); // Get loan from Compound in USDC ERC20Detailed token = __underlyingToken(compoundTokenAddr); token.safeApprove(compoundTokenAddr, 0); // Clear token allowance of Compound token.safeApprove(compoundTokenAddr, actualTokenAmount); // Approve token transfer to Compound require(market.mint(actualTokenAmount) == 0); // Transfer tokens into Compound as supply token.safeApprove(compoundTokenAddr, 0); // Clear token allowance of Compound require(CUSDC.borrow(loanAmountInUSDC) == 0);// Take out loan in USDC (bool negLiquidity, ) = getCurrentLiquidityInUSDC(); require(!negLiquidity); // Ensure account liquidity is positive // Convert borrowed USDC to longing token __sellUSDCForToken(loanAmountInUSDC); // Repay leftover USDC to avoid complications if (usdc.balanceOf(address(this)) > 0) { uint256 repayAmount = usdc.balanceOf(address(this)); usdc.safeApprove(address(CUSDC), 0); usdc.safeApprove(address(CUSDC), repayAmount); require(CUSDC.repayBorrow(repayAmount) == 0); usdc.safeApprove(address(CUSDC), 0); } } function sellOrder(uint256 _minPrice, uint256 _maxPrice) public onlyOwner isValidPrice(_minPrice, _maxPrice) returns (uint256 _inputAmount, uint256 _outputAmount) { require(buyTime > 0); // Ensure the order has been executed require(isSold == false); isSold = true; // Siphon remaining collateral by repaying x USDC and getting back 1.5x USDC collateral // Repeat to ensure debt is exhausted CERC20 market = CERC20(compoundTokenAddr); ERC20Detailed token = __underlyingToken(compoundTokenAddr); for (uint256 i = 0; i < MAX_REPAY_STEPS; i++) { uint256 currentDebt = getCurrentBorrowInUSDC(); if (currentDebt > NEGLIGIBLE_DEBT) { // Determine amount to be repaid this step uint256 currentBalance = getCurrentCashInUSDC(); uint256 repayAmount = 0; // amount to be repaid in USDC if (currentDebt <= currentBalance) { // Has enough money, repay all debt repayAmount = currentDebt; } else { // Doesn't have enough money, repay whatever we can repay repayAmount = currentBalance; } // Repay debt repayLoan(repayAmount); } // Withdraw all available liquidity (bool isNeg, uint256 liquidity) = getCurrentLiquidityInUSDC(); if (!isNeg) { liquidity = __usdcToToken(compoundTokenAddr, liquidity); uint256 errorCode = market.redeemUnderlying(liquidity.mul(PRECISION.sub(DEFAULT_LIQUIDITY_SLIPPAGE)).div(PRECISION)); if (errorCode != 0) { // error // try again with fallback slippage errorCode = market.redeemUnderlying(liquidity.mul(PRECISION.sub(FALLBACK_LIQUIDITY_SLIPPAGE)).div(PRECISION)); if (errorCode != 0) { // error // try again with max slippage market.redeemUnderlying(liquidity.mul(PRECISION.sub(MAX_LIQUIDITY_SLIPPAGE)).div(PRECISION)); } } } if (currentDebt <= NEGLIGIBLE_DEBT) { break; } } // Sell all longing token to USDC __sellTokenForUSDC(token.balanceOf(address(this))); // Send USDC back to PeakDeFiFund and return _inputAmount = collateralAmountInUSDC; _outputAmount = usdc.balanceOf(address(this)); outputAmount = _outputAmount; usdc.safeTransfer(owner(), usdc.balanceOf(address(this))); uint256 leftoverTokens = token.balanceOf(address(this)); if (leftoverTokens > 0) { token.safeTransfer(owner(), leftoverTokens); // Send back potential leftover tokens } } // Allows manager to repay loan to avoid liquidation function repayLoan(uint256 _repayAmountInUSDC) public onlyOwner { require(buyTime > 0); // Ensure the order has been executed // Convert longing token to USDC uint256 repayAmountInToken = __usdcToToken(compoundTokenAddr, _repayAmountInUSDC); (uint256 actualUSDCAmount,) = __sellTokenForUSDC(repayAmountInToken); // Check if amount is greater than borrow balance uint256 currentDebt = CUSDC.borrowBalanceCurrent(address(this)); if (actualUSDCAmount > currentDebt) { actualUSDCAmount = currentDebt; } // Repay loan to Compound usdc.safeApprove(address(CUSDC), 0); usdc.safeApprove(address(CUSDC), actualUSDCAmount); require(CUSDC.repayBorrow(actualUSDCAmount) == 0); usdc.safeApprove(address(CUSDC), 0); } function getMarketCollateralFactor() public view returns (uint256) { (, uint256 ratio) = COMPTROLLER.markets(address(compoundTokenAddr)); return ratio; } function getCurrentCollateralInUSDC() public returns (uint256 _amount) { CERC20 market = CERC20(compoundTokenAddr); uint256 supply = __tokenToUSDC(compoundTokenAddr, market.balanceOf(address(this)).mul(market.exchangeRateCurrent()).div(PRECISION)); return supply; } function getCurrentBorrowInUSDC() public returns (uint256 _amount) { uint256 borrow = CUSDC.borrowBalanceCurrent(address(this)); return borrow; } function getCurrentCashInUSDC() public view returns (uint256 _amount) { ERC20Detailed token = __underlyingToken(compoundTokenAddr); uint256 cash = __tokenToUSDC(compoundTokenAddr, getBalance(token, address(this))); return cash; } }
pragma solidity 0.5.17; import "./CompoundOrder.sol"; contract LongCEtherOrder is CompoundOrder { modifier isValidPrice(uint256 _minPrice, uint256 _maxPrice) { // Ensure token's price is between _minPrice and _maxPrice uint256 tokenPrice = ORACLE.getUnderlyingPrice(compoundTokenAddr); // Get the longing token's price in USD require(tokenPrice > 0); // Ensure asset exists on Compound require(tokenPrice >= _minPrice && tokenPrice <= _maxPrice); // Ensure price is within range _; } function executeOrder(uint256 _minPrice, uint256 _maxPrice) public onlyOwner isValidToken(compoundTokenAddr) isValidPrice(_minPrice, _maxPrice) { buyTime = now; // Get funds in USDC from PeakDeFiFund usdc.safeTransferFrom(owner(), address(this), collateralAmountInUSDC); // Transfer USDC from PeakDeFiFund // Convert received USDC to longing token (,uint256 actualTokenAmount) = __sellUSDCForToken(collateralAmountInUSDC); // Enter Compound markets CEther market = CEther(compoundTokenAddr); address[] memory markets = new address[](2); markets[0] = compoundTokenAddr; markets[1] = address(CUSDC); uint[] memory errors = COMPTROLLER.enterMarkets(markets); require(errors[0] == 0 && errors[1] == 0); // Get loan from Compound in USDC market.mint.value(actualTokenAmount)(); // Transfer tokens into Compound as supply require(CUSDC.borrow(loanAmountInUSDC) == 0);// Take out loan in USDC (bool negLiquidity, ) = getCurrentLiquidityInUSDC(); require(!negLiquidity); // Ensure account liquidity is positive // Convert borrowed USDC to longing token __sellUSDCForToken(loanAmountInUSDC); // Repay leftover USDC to avoid complications if (usdc.balanceOf(address(this)) > 0) { uint256 repayAmount = usdc.balanceOf(address(this)); usdc.safeApprove(address(CUSDC), 0); usdc.safeApprove(address(CUSDC), repayAmount); require(CUSDC.repayBorrow(repayAmount) == 0); usdc.safeApprove(address(CUSDC), 0); } } function sellOrder(uint256 _minPrice, uint256 _maxPrice) public onlyOwner isValidPrice(_minPrice, _maxPrice) returns (uint256 _inputAmount, uint256 _outputAmount) { require(buyTime > 0); // Ensure the order has been executed require(isSold == false); isSold = true; // Siphon remaining collateral by repaying x USDC and getting back 1.5x USDC collateral // Repeat to ensure debt is exhausted CEther market = CEther(compoundTokenAddr); for (uint256 i = 0; i < MAX_REPAY_STEPS; i++) { uint256 currentDebt = getCurrentBorrowInUSDC(); if (currentDebt > NEGLIGIBLE_DEBT) { // Determine amount to be repaid this step uint256 currentBalance = getCurrentCashInUSDC(); uint256 repayAmount = 0; // amount to be repaid in USDC if (currentDebt <= currentBalance) { // Has enough money, repay all debt repayAmount = currentDebt; } else { // Doesn't have enough money, repay whatever we can repay repayAmount = currentBalance; } // Repay debt repayLoan(repayAmount); } // Withdraw all available liquidity (bool isNeg, uint256 liquidity) = getCurrentLiquidityInUSDC(); if (!isNeg) { liquidity = __usdcToToken(compoundTokenAddr, liquidity); uint256 errorCode = market.redeemUnderlying(liquidity.mul(PRECISION.sub(DEFAULT_LIQUIDITY_SLIPPAGE)).div(PRECISION)); if (errorCode != 0) { // error // try again with fallback slippage errorCode = market.redeemUnderlying(liquidity.mul(PRECISION.sub(FALLBACK_LIQUIDITY_SLIPPAGE)).div(PRECISION)); if (errorCode != 0) { // error // try again with max slippage market.redeemUnderlying(liquidity.mul(PRECISION.sub(MAX_LIQUIDITY_SLIPPAGE)).div(PRECISION)); } } } if (currentDebt <= NEGLIGIBLE_DEBT) { break; } } // Sell all longing token to USDC __sellTokenForUSDC(address(this).balance); // Send USDC back to PeakDeFiFund and return _inputAmount = collateralAmountInUSDC; _outputAmount = usdc.balanceOf(address(this)); outputAmount = _outputAmount; usdc.safeTransfer(owner(), usdc.balanceOf(address(this))); toPayableAddr(owner()).transfer(address(this).balance); // Send back potential leftover tokens } // Allows manager to repay loan to avoid liquidation function repayLoan(uint256 _repayAmountInUSDC) public onlyOwner { require(buyTime > 0); // Ensure the order has been executed // Convert longing token to USDC uint256 repayAmountInToken = __usdcToToken(compoundTokenAddr, _repayAmountInUSDC); (uint256 actualUSDCAmount,) = __sellTokenForUSDC(repayAmountInToken); // Check if amount is greater than borrow balance uint256 currentDebt = CUSDC.borrowBalanceCurrent(address(this)); if (actualUSDCAmount > currentDebt) { actualUSDCAmount = currentDebt; } // Repay loan to Compound usdc.safeApprove(address(CUSDC), 0); usdc.safeApprove(address(CUSDC), actualUSDCAmount); require(CUSDC.repayBorrow(actualUSDCAmount) == 0); usdc.safeApprove(address(CUSDC), 0); } function getMarketCollateralFactor() public view returns (uint256) { (, uint256 ratio) = COMPTROLLER.markets(address(compoundTokenAddr)); return ratio; } function getCurrentCollateralInUSDC() public returns (uint256 _amount) { CEther market = CEther(compoundTokenAddr); uint256 supply = __tokenToUSDC(compoundTokenAddr, market.balanceOf(address(this)).mul(market.exchangeRateCurrent()).div(PRECISION)); return supply; } function getCurrentBorrowInUSDC() public returns (uint256 _amount) { uint256 borrow = CUSDC.borrowBalanceCurrent(address(this)); return borrow; } function getCurrentCashInUSDC() public view returns (uint256 _amount) { ERC20Detailed token = __underlyingToken(compoundTokenAddr); uint256 cash = __tokenToUSDC(compoundTokenAddr, getBalance(token, address(this))); return cash; } }
pragma solidity 0.5.17; import "./CompoundOrder.sol"; contract ShortCERC20Order is CompoundOrder { modifier isValidPrice(uint256 _minPrice, uint256 _maxPrice) { // Ensure token's price is between _minPrice and _maxPrice uint256 tokenPrice = ORACLE.getUnderlyingPrice(compoundTokenAddr); // Get the shorting token's price in USD require(tokenPrice > 0); // Ensure asset exists on Compound require(tokenPrice >= _minPrice && tokenPrice <= _maxPrice); // Ensure price is within range _; } function executeOrder(uint256 _minPrice, uint256 _maxPrice) public onlyOwner isValidToken(compoundTokenAddr) isValidPrice(_minPrice, _maxPrice) { buyTime = now; // Get funds in USDC from PeakDeFiFund usdc.safeTransferFrom(owner(), address(this), collateralAmountInUSDC); // Transfer USDC from PeakDeFiFund // Enter Compound markets CERC20 market = CERC20(compoundTokenAddr); address[] memory markets = new address[](2); markets[0] = compoundTokenAddr; markets[1] = address(CUSDC); uint[] memory errors = COMPTROLLER.enterMarkets(markets); require(errors[0] == 0 && errors[1] == 0); // Get loan from Compound in tokenAddr uint256 loanAmountInToken = __usdcToToken(compoundTokenAddr, loanAmountInUSDC); usdc.safeApprove(address(CUSDC), 0); // Clear USDC allowance of Compound USDC market usdc.safeApprove(address(CUSDC), collateralAmountInUSDC); // Approve USDC transfer to Compound USDC market require(CUSDC.mint(collateralAmountInUSDC) == 0); // Transfer USDC into Compound as supply usdc.safeApprove(address(CUSDC), 0); require(market.borrow(loanAmountInToken) == 0);// Take out loan (bool negLiquidity, ) = getCurrentLiquidityInUSDC(); require(!negLiquidity); // Ensure account liquidity is positive // Convert loaned tokens to USDC (uint256 actualUSDCAmount,) = __sellTokenForUSDC(loanAmountInToken); loanAmountInUSDC = actualUSDCAmount; // Change loan amount to actual USDC received // Repay leftover tokens to avoid complications ERC20Detailed token = __underlyingToken(compoundTokenAddr); if (token.balanceOf(address(this)) > 0) { uint256 repayAmount = token.balanceOf(address(this)); token.safeApprove(compoundTokenAddr, 0); token.safeApprove(compoundTokenAddr, repayAmount); require(market.repayBorrow(repayAmount) == 0); token.safeApprove(compoundTokenAddr, 0); } } function sellOrder(uint256 _minPrice, uint256 _maxPrice) public onlyOwner isValidPrice(_minPrice, _maxPrice) returns (uint256 _inputAmount, uint256 _outputAmount) { require(buyTime > 0); // Ensure the order has been executed require(isSold == false); isSold = true; // Siphon remaining collateral by repaying x USDC and getting back 1.5x USDC collateral // Repeat to ensure debt is exhausted for (uint256 i = 0; i < MAX_REPAY_STEPS; i++) { uint256 currentDebt = getCurrentBorrowInUSDC(); if (currentDebt > NEGLIGIBLE_DEBT) { // Determine amount to be repaid this step uint256 currentBalance = getCurrentCashInUSDC(); uint256 repayAmount = 0; // amount to be repaid in USDC if (currentDebt <= currentBalance) { // Has enough money, repay all debt repayAmount = currentDebt; } else { // Doesn't have enough money, repay whatever we can repay repayAmount = currentBalance; } // Repay debt repayLoan(repayAmount); } // Withdraw all available liquidity (bool isNeg, uint256 liquidity) = getCurrentLiquidityInUSDC(); if (!isNeg) { uint256 errorCode = CUSDC.redeemUnderlying(liquidity.mul(PRECISION.sub(DEFAULT_LIQUIDITY_SLIPPAGE)).div(PRECISION)); if (errorCode != 0) { // error // try again with fallback slippage errorCode = CUSDC.redeemUnderlying(liquidity.mul(PRECISION.sub(FALLBACK_LIQUIDITY_SLIPPAGE)).div(PRECISION)); if (errorCode != 0) { // error // try again with max slippage CUSDC.redeemUnderlying(liquidity.mul(PRECISION.sub(MAX_LIQUIDITY_SLIPPAGE)).div(PRECISION)); } } } if (currentDebt <= NEGLIGIBLE_DEBT) { break; } } // Send USDC back to PeakDeFiFund and return _inputAmount = collateralAmountInUSDC; _outputAmount = usdc.balanceOf(address(this)); outputAmount = _outputAmount; usdc.safeTransfer(owner(), usdc.balanceOf(address(this))); } // Allows manager to repay loan to avoid liquidation function repayLoan(uint256 _repayAmountInUSDC) public onlyOwner { require(buyTime > 0); // Ensure the order has been executed // Convert USDC to shorting token (,uint256 actualTokenAmount) = __sellUSDCForToken(_repayAmountInUSDC); // Check if amount is greater than borrow balance CERC20 market = CERC20(compoundTokenAddr); uint256 currentDebt = market.borrowBalanceCurrent(address(this)); if (actualTokenAmount > currentDebt) { actualTokenAmount = currentDebt; } // Repay loan to Compound ERC20Detailed token = __underlyingToken(compoundTokenAddr); token.safeApprove(compoundTokenAddr, 0); token.safeApprove(compoundTokenAddr, actualTokenAmount); require(market.repayBorrow(actualTokenAmount) == 0); token.safeApprove(compoundTokenAddr, 0); } function getMarketCollateralFactor() public view returns (uint256) { (, uint256 ratio) = COMPTROLLER.markets(address(CUSDC)); return ratio; } function getCurrentCollateralInUSDC() public returns (uint256 _amount) { uint256 supply = CUSDC.balanceOf(address(this)).mul(CUSDC.exchangeRateCurrent()).div(PRECISION); return supply; } function getCurrentBorrowInUSDC() public returns (uint256 _amount) { CERC20 market = CERC20(compoundTokenAddr); uint256 borrow = __tokenToUSDC(compoundTokenAddr, market.borrowBalanceCurrent(address(this))); return borrow; } function getCurrentCashInUSDC() public view returns (uint256 _amount) { uint256 cash = getBalance(usdc, address(this)); return cash; } }
pragma solidity 0.5.17; import "./CompoundOrder.sol"; contract ShortCEtherOrder is CompoundOrder { modifier isValidPrice(uint256 _minPrice, uint256 _maxPrice) { // Ensure token's price is between _minPrice and _maxPrice uint256 tokenPrice = ORACLE.getUnderlyingPrice(compoundTokenAddr); // Get the shorting token's price in USD require(tokenPrice > 0); // Ensure asset exists on Compound require(tokenPrice >= _minPrice && tokenPrice <= _maxPrice); // Ensure price is within range _; } function executeOrder(uint256 _minPrice, uint256 _maxPrice) public onlyOwner isValidToken(compoundTokenAddr) isValidPrice(_minPrice, _maxPrice) { buyTime = now; // Get funds in USDC from PeakDeFiFund usdc.safeTransferFrom(owner(), address(this), collateralAmountInUSDC); // Transfer USDC from PeakDeFiFund // Enter Compound markets CEther market = CEther(compoundTokenAddr); address[] memory markets = new address[](2); markets[0] = compoundTokenAddr; markets[1] = address(CUSDC); uint[] memory errors = COMPTROLLER.enterMarkets(markets); require(errors[0] == 0 && errors[1] == 0); // Get loan from Compound in tokenAddr uint256 loanAmountInToken = __usdcToToken(compoundTokenAddr, loanAmountInUSDC); usdc.safeApprove(address(CUSDC), 0); // Clear USDC allowance of Compound USDC market usdc.safeApprove(address(CUSDC), collateralAmountInUSDC); // Approve USDC transfer to Compound USDC market require(CUSDC.mint(collateralAmountInUSDC) == 0); // Transfer USDC into Compound as supply usdc.safeApprove(address(CUSDC), 0); require(market.borrow(loanAmountInToken) == 0);// Take out loan (bool negLiquidity, ) = getCurrentLiquidityInUSDC(); require(!negLiquidity); // Ensure account liquidity is positive // Convert loaned tokens to USDC (uint256 actualUSDCAmount,) = __sellTokenForUSDC(loanAmountInToken); loanAmountInUSDC = actualUSDCAmount; // Change loan amount to actual USDC received // Repay leftover tokens to avoid complications if (address(this).balance > 0) { uint256 repayAmount = address(this).balance; market.repayBorrow.value(repayAmount)(); } } function sellOrder(uint256 _minPrice, uint256 _maxPrice) public onlyOwner isValidPrice(_minPrice, _maxPrice) returns (uint256 _inputAmount, uint256 _outputAmount) { require(buyTime > 0); // Ensure the order has been executed require(isSold == false); isSold = true; // Siphon remaining collateral by repaying x USDC and getting back 1.5x USDC collateral // Repeat to ensure debt is exhausted for (uint256 i = 0; i < MAX_REPAY_STEPS; i = i++) { uint256 currentDebt = getCurrentBorrowInUSDC(); if (currentDebt > NEGLIGIBLE_DEBT) { // Determine amount to be repaid this step uint256 currentBalance = getCurrentCashInUSDC(); uint256 repayAmount = 0; // amount to be repaid in USDC if (currentDebt <= currentBalance) { // Has enough money, repay all debt repayAmount = currentDebt; } else { // Doesn't have enough money, repay whatever we can repay repayAmount = currentBalance; } // Repay debt repayLoan(repayAmount); } // Withdraw all available liquidity (bool isNeg, uint256 liquidity) = getCurrentLiquidityInUSDC(); if (!isNeg) { uint256 errorCode = CUSDC.redeemUnderlying(liquidity.mul(PRECISION.sub(DEFAULT_LIQUIDITY_SLIPPAGE)).div(PRECISION)); if (errorCode != 0) { // error // try again with fallback slippage errorCode = CUSDC.redeemUnderlying(liquidity.mul(PRECISION.sub(FALLBACK_LIQUIDITY_SLIPPAGE)).div(PRECISION)); if (errorCode != 0) { // error // try again with max slippage CUSDC.redeemUnderlying(liquidity.mul(PRECISION.sub(MAX_LIQUIDITY_SLIPPAGE)).div(PRECISION)); } } } if (currentDebt <= NEGLIGIBLE_DEBT) { break; } } // Send USDC back to PeakDeFiFund and return _inputAmount = collateralAmountInUSDC; _outputAmount = usdc.balanceOf(address(this)); outputAmount = _outputAmount; usdc.safeTransfer(owner(), usdc.balanceOf(address(this))); } // Allows manager to repay loan to avoid liquidation function repayLoan(uint256 _repayAmountInUSDC) public onlyOwner { require(buyTime > 0); // Ensure the order has been executed // Convert USDC to shorting token (,uint256 actualTokenAmount) = __sellUSDCForToken(_repayAmountInUSDC); // Check if amount is greater than borrow balance CEther market = CEther(compoundTokenAddr); uint256 currentDebt = market.borrowBalanceCurrent(address(this)); if (actualTokenAmount > currentDebt) { actualTokenAmount = currentDebt; } // Repay loan to Compound market.repayBorrow.value(actualTokenAmount)(); } function getMarketCollateralFactor() public view returns (uint256) { (, uint256 ratio) = COMPTROLLER.markets(address(CUSDC)); return ratio; } function getCurrentCollateralInUSDC() public returns (uint256 _amount) { uint256 supply = CUSDC.balanceOf(address(this)).mul(CUSDC.exchangeRateCurrent()).div(PRECISION); return supply; } function getCurrentBorrowInUSDC() public returns (uint256 _amount) { CEther market = CEther(compoundTokenAddr); uint256 borrow = __tokenToUSDC(compoundTokenAddr, market.borrowBalanceCurrent(address(this))); return borrow; } function getCurrentCashInUSDC() public view returns (uint256 _amount) { uint256 cash = getBalance(usdc, address(this)); return cash; } }
pragma solidity 0.5.17; /* The MIT License (MIT) Copyright (c) 2018 Murray Software, LLC. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ //solhint-disable max-line-length //solhint-disable no-inline-assembly contract CloneFactory { function createClone(address target) internal returns (address result) { bytes20 targetBytes = bytes20(target); assembly { let clone := mload(0x40) mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(clone, 0x14), targetBytes) mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) result := create(0, clone, 0x37) } } function isClone(address target, address query) internal view returns (bool result) { bytes20 targetBytes = bytes20(target); assembly { let clone := mload(0x40) mstore(clone, 0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000) mstore(add(clone, 0xa), targetBytes) mstore(add(clone, 0x1e), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) let other := add(clone, 0x40) extcodecopy(query, other, 0, 0x2d) result := and( eq(mload(clone), mload(other)), eq(mload(add(clone, 0xd)), mload(add(other, 0xd))) ) } } }
pragma solidity 0.5.17; interface IMiniMeToken { function balanceOf(address _owner) external view returns (uint256 balance); function totalSupply() external view returns(uint); function generateTokens(address _owner, uint _amount) external returns (bool); function destroyTokens(address _owner, uint _amount) external returns (bool); function totalSupplyAt(uint _blockNumber) external view returns(uint); function balanceOfAt(address _holder, uint _blockNumber) external view returns (uint); function transferOwnership(address newOwner) external; }
pragma solidity ^0.5.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. * * _Since v2.5.0:_ this module is now much more gas efficient, given net gas * metering changes introduced in the Istanbul hardfork. */ contract ReentrancyGuard { bool private _notEntered; function __initReentrancyGuard() internal { // Storing an initial non-zero value makes deployment a bit more // expensive, but in exchange the refund on every call to nonReentrant // will be lower in amount. Since refunds are capped to a percetange of // the total transaction's gas, it is best to keep them low in cases // like this one, to increase the likelihood of the full refund coming // into effect. _notEntered = true; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_notEntered, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _notEntered = false; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _notEntered = true; } }
pragma solidity 0.5.17; contract Migrations { address public owner; uint public last_completed_migration; modifier restricted() { if (msg.sender == owner) _; } constructor() public { owner = msg.sender; } function setCompleted(uint completed) public restricted { last_completed_migration = completed; } function upgrade(address new_address) public restricted { Migrations upgraded = Migrations(new_address); upgraded.setCompleted(last_completed_migration); } }
pragma solidity 0.5.17; // interface for contract_v6/UniswapOracle.sol interface IUniswapOracle { function update() external returns (bool success); function consult(address token, uint256 amountIn) external view returns (uint256 amountOut); }
pragma solidity 0.5.17; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20Capped.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol"; contract PeakToken is ERC20, ERC20Detailed, ERC20Capped, ERC20Burnable { constructor( string memory name, string memory symbol, uint8 decimals, uint256 cap ) ERC20Detailed(name, symbol, decimals) ERC20Capped(cap) public {} }
pragma solidity ^0.5.0; import "../../GSN/Context.sol"; import "./IERC20.sol"; import "../../math/SafeMath.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 {ERC20Mintable}. * * 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; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view 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 returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public 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 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 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 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 { 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); } /** @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 { 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); } /** * @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 { 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); } /** * @dev 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. */ 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); } /** * @dev Destroys `amount` tokens from `account`.`amount` is then deducted * from the caller's allowance. * * See {_burn} and {_approve}. */ function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } }
pragma solidity ^0.5.0; import "./ERC20Mintable.sol"; /** * @dev Extension of {ERC20Mintable} that adds a cap to the supply of tokens. */ contract ERC20Capped is ERC20Mintable { uint256 private _cap; /** * @dev Sets the value of the `cap`. This value is immutable, it can only be * set once during construction. */ constructor (uint256 cap) public { require(cap > 0, "ERC20Capped: cap is 0"); _cap = cap; } /** * @dev Returns the cap on the token's total supply. */ function cap() public view returns (uint256) { return _cap; } /** * @dev See {ERC20Mintable-mint}. * * Requirements: * * - `value` must not cause the total supply to go over the cap. */ function _mint(address account, uint256 value) internal { require(totalSupply().add(value) <= _cap, "ERC20Capped: cap exceeded"); super._mint(account, value); } }
pragma solidity ^0.5.0; import "./ERC20.sol"; import "../../access/roles/MinterRole.sol"; /** * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole}, * which have permission to mint (create) new tokens as they see fit. * * At construction, the deployer of the contract is the only minter. */ contract ERC20Mintable is ERC20, MinterRole { /** * @dev See {ERC20-_mint}. * * Requirements: * * - the caller must have the {MinterRole}. */ function mint(address account, uint256 amount) public onlyMinter returns (bool) { _mint(account, amount); return true; } }
pragma solidity ^0.5.0; import "../../GSN/Context.sol"; import "../Roles.sol"; contract MinterRole is Context { using Roles for Roles.Role; event MinterAdded(address indexed account); event MinterRemoved(address indexed account); Roles.Role private _minters; constructor () internal { _addMinter(_msgSender()); } modifier onlyMinter() { require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role"); _; } function isMinter(address account) public view returns (bool) { return _minters.has(account); } function addMinter(address account) public onlyMinter { _addMinter(account); } function renounceMinter() public { _removeMinter(_msgSender()); } function _addMinter(address account) internal { _minters.add(account); emit MinterAdded(account); } function _removeMinter(address account) internal { _minters.remove(account); emit MinterRemoved(account); } }
pragma solidity ^0.5.0; /** * @title Roles * @dev Library for managing addresses assigned to a Role. */ library Roles { struct Role { mapping (address => bool) bearer; } /** * @dev Give an account access to this role. */ function add(Role storage role, address account) internal { require(!has(role, account), "Roles: account already has role"); role.bearer[account] = true; } /** * @dev Remove an account's access to this role. */ function remove(Role storage role, address account) internal { require(has(role, account), "Roles: account does not have role"); role.bearer[account] = false; } /** * @dev Check if an account has this role. * @return bool */ function has(Role storage role, address account) internal view returns (bool) { require(account != address(0), "Roles: account is the zero address"); return role.bearer[account]; } }
pragma solidity ^0.5.0; import "../../GSN/Context.sol"; import "./ERC20.sol"; /** * @dev 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). */ contract ERC20Burnable is Context, ERC20 { /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public { _burn(_msgSender(), amount); } /** * @dev See {ERC20-_burnFrom}. */ function burnFrom(address account, uint256 amount) public { _burnFrom(account, amount); } }
pragma solidity ^0.5.0; import "../../GSN/Context.sol"; import "../Roles.sol"; contract SignerRole is Context { using Roles for Roles.Role; event SignerAdded(address indexed account); event SignerRemoved(address indexed account); Roles.Role private _signers; constructor () internal { _addSigner(_msgSender()); } modifier onlySigner() { require(isSigner(_msgSender()), "SignerRole: caller does not have the Signer role"); _; } function isSigner(address account) public view returns (bool) { return _signers.has(account); } function addSigner(address account) public onlySigner { _addSigner(account); } function renounceSigner() public { _removeSigner(_msgSender()); } function _addSigner(address account) internal { _signers.add(account); emit SignerAdded(account); } function _removeSigner(address account) internal { _signers.remove(account); emit SignerRemoved(account); } }
pragma solidity 0.5.17; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "../reward/PeakReward.sol"; import "../PeakToken.sol"; contract PeakStaking { using SafeMath for uint256; using SafeERC20 for PeakToken; event CreateStake( uint256 idx, address user, address referrer, uint256 stakeAmount, uint256 stakeTimeInDays, uint256 interestAmount ); event ReceiveStakeReward(uint256 idx, address user, uint256 rewardAmount); event WithdrawReward(uint256 idx, address user, uint256 rewardAmount); event WithdrawStake(uint256 idx, address user); uint256 internal constant PRECISION = 10**18; uint256 internal constant PEAK_PRECISION = 10**8; uint256 internal constant INTEREST_SLOPE = 2 * (10**8); // Interest rate factor drops to 0 at 5B mintedPeakTokens uint256 internal constant BIGGER_BONUS_DIVISOR = 10**15; // biggerBonus = stakeAmount / (10 million peak) uint256 internal constant MAX_BIGGER_BONUS = 10**17; // biggerBonus <= 10% uint256 internal constant DAILY_BASE_REWARD = 15 * (10**14); // dailyBaseReward = 0.0015 uint256 internal constant DAILY_GROWING_REWARD = 10**12; // dailyGrowingReward = 1e-6 uint256 internal constant MAX_STAKE_PERIOD = 1000; // Max staking time is 1000 days uint256 internal constant MIN_STAKE_PERIOD = 10; // Min staking time is 10 days uint256 internal constant DAY_IN_SECONDS = 86400; uint256 internal constant COMMISSION_RATE = 20 * (10**16); // 20% uint256 internal constant REFERRAL_STAKER_BONUS = 3 * (10**16); // 3% uint256 internal constant YEAR_IN_DAYS = 365; uint256 public constant PEAK_MINT_CAP = 7 * 10**16; // 700 million PEAK struct Stake { address staker; uint256 stakeAmount; uint256 interestAmount; uint256 withdrawnInterestAmount; uint256 stakeTimestamp; uint256 stakeTimeInDays; bool active; } Stake[] public stakeList; mapping(address => uint256) public userStakeAmount; uint256 public mintedPeakTokens; bool public initialized; PeakToken public peakToken; PeakReward public peakReward; constructor(address _peakToken) public { peakToken = PeakToken(_peakToken); } function init(address _peakReward) public { require(!initialized, "PeakStaking: Already initialized"); initialized = true; peakReward = PeakReward(_peakReward); } function stake( uint256 stakeAmount, uint256 stakeTimeInDays, address referrer ) public returns (uint256 stakeIdx) { require( stakeTimeInDays >= MIN_STAKE_PERIOD, "PeakStaking: stakeTimeInDays < MIN_STAKE_PERIOD" ); require( stakeTimeInDays <= MAX_STAKE_PERIOD, "PeakStaking: stakeTimeInDays > MAX_STAKE_PERIOD" ); // record stake uint256 interestAmount = getInterestAmount( stakeAmount, stakeTimeInDays ); stakeIdx = stakeList.length; stakeList.push( Stake({ staker: msg.sender, stakeAmount: stakeAmount, interestAmount: interestAmount, withdrawnInterestAmount: 0, stakeTimestamp: now, stakeTimeInDays: stakeTimeInDays, active: true }) ); mintedPeakTokens = mintedPeakTokens.add(interestAmount); userStakeAmount[msg.sender] = userStakeAmount[msg.sender].add( stakeAmount ); // transfer PEAK from msg.sender peakToken.safeTransferFrom(msg.sender, address(this), stakeAmount); // mint PEAK interest peakToken.mint(address(this), interestAmount); // handle referral if (peakReward.canRefer(msg.sender, referrer)) { peakReward.refer(msg.sender, referrer); } address actualReferrer = peakReward.referrerOf(msg.sender); if (actualReferrer != address(0)) { // pay referral bonus to referrer uint256 rawCommission = interestAmount.mul(COMMISSION_RATE).div( PRECISION ); peakToken.mint(address(this), rawCommission); peakToken.safeApprove(address(peakReward), rawCommission); uint256 leftoverAmount = peakReward.payCommission( actualReferrer, address(peakToken), rawCommission, true ); peakToken.burn(leftoverAmount); // pay referral bonus to staker uint256 referralStakerBonus = interestAmount .mul(REFERRAL_STAKER_BONUS) .div(PRECISION); peakToken.mint(msg.sender, referralStakerBonus); mintedPeakTokens = mintedPeakTokens.add( rawCommission.sub(leftoverAmount).add(referralStakerBonus) ); emit ReceiveStakeReward(stakeIdx, msg.sender, referralStakerBonus); } require(mintedPeakTokens <= PEAK_MINT_CAP, "PeakStaking: reached cap"); emit CreateStake( stakeIdx, msg.sender, actualReferrer, stakeAmount, stakeTimeInDays, interestAmount ); } function withdraw(uint256 stakeIdx) public { Stake storage stakeObj = stakeList[stakeIdx]; require( stakeObj.staker == msg.sender, "PeakStaking: Sender not staker" ); require(stakeObj.active, "PeakStaking: Not active"); // calculate amount that can be withdrawn uint256 stakeTimeInSeconds = stakeObj.stakeTimeInDays.mul( DAY_IN_SECONDS ); uint256 withdrawAmount; if (now >= stakeObj.stakeTimestamp.add(stakeTimeInSeconds)) { // matured, withdraw all withdrawAmount = stakeObj .stakeAmount .add(stakeObj.interestAmount) .sub(stakeObj.withdrawnInterestAmount); stakeObj.active = false; stakeObj.withdrawnInterestAmount = stakeObj.interestAmount; userStakeAmount[msg.sender] = userStakeAmount[msg.sender].sub( stakeObj.stakeAmount ); emit WithdrawReward( stakeIdx, msg.sender, stakeObj.interestAmount.sub(stakeObj.withdrawnInterestAmount) ); emit WithdrawStake(stakeIdx, msg.sender); } else { // not mature, partial withdraw withdrawAmount = stakeObj .interestAmount .mul(uint256(now).sub(stakeObj.stakeTimestamp)) .div(stakeTimeInSeconds) .sub(stakeObj.withdrawnInterestAmount); // record withdrawal stakeObj.withdrawnInterestAmount = stakeObj .withdrawnInterestAmount .add(withdrawAmount); emit WithdrawReward(stakeIdx, msg.sender, withdrawAmount); } // withdraw interest to sender peakToken.safeTransfer(msg.sender, withdrawAmount); } function getInterestAmount(uint256 stakeAmount, uint256 stakeTimeInDays) public view returns (uint256) { uint256 earlyFactor = _earlyFactor(mintedPeakTokens); uint256 biggerBonus = stakeAmount.mul(PRECISION).div( BIGGER_BONUS_DIVISOR ); if (biggerBonus > MAX_BIGGER_BONUS) { biggerBonus = MAX_BIGGER_BONUS; } // convert yearly bigger bonus to stake time biggerBonus = biggerBonus.mul(stakeTimeInDays).div(YEAR_IN_DAYS); uint256 longerBonus = _longerBonus(stakeTimeInDays); uint256 interestRate = biggerBonus.add(longerBonus).mul(earlyFactor).div( PRECISION ); uint256 interestAmount = stakeAmount.mul(interestRate).div(PRECISION); return interestAmount; } function _longerBonus(uint256 stakeTimeInDays) internal pure returns (uint256) { return DAILY_BASE_REWARD.mul(stakeTimeInDays).add( DAILY_GROWING_REWARD .mul(stakeTimeInDays) .mul(stakeTimeInDays.add(1)) .div(2) ); } function _earlyFactor(uint256 _mintedPeakTokens) internal pure returns (uint256) { uint256 tmp = INTEREST_SLOPE.mul(_mintedPeakTokens).div(PEAK_PRECISION); if (tmp > PRECISION) { return 0; } return PRECISION.sub(tmp); } }
pragma solidity 0.5.17; import "./lib/CloneFactory.sol"; import "./tokens/minime/MiniMeToken.sol"; import "./PeakDeFiFund.sol"; import "./PeakDeFiProxy.sol"; import "@openzeppelin/contracts/utils/Address.sol"; contract PeakDeFiFactory is CloneFactory { using Address for address; event CreateFund(address fund); event InitFund(address fund, address proxy); address public usdcAddr; address payable public kyberAddr; address payable public oneInchAddr; address payable public peakdefiFund; address public peakdefiLogic; address public peakdefiLogic2; address public peakdefiLogic3; address public peakRewardAddr; address public peakStakingAddr; MiniMeTokenFactory public minimeFactory; mapping(address => address) public fundCreator; constructor( address _usdcAddr, address payable _kyberAddr, address payable _oneInchAddr, address payable _peakdefiFund, address _peakdefiLogic, address _peakdefiLogic2, address _peakdefiLogic3, address _peakRewardAddr, address _peakStakingAddr, address _minimeFactoryAddr ) public { usdcAddr = _usdcAddr; kyberAddr = _kyberAddr; oneInchAddr = _oneInchAddr; peakdefiFund = _peakdefiFund; peakdefiLogic = _peakdefiLogic; peakdefiLogic2 = _peakdefiLogic2; peakdefiLogic3 = _peakdefiLogic3; peakRewardAddr = _peakRewardAddr; peakStakingAddr = _peakStakingAddr; minimeFactory = MiniMeTokenFactory(_minimeFactoryAddr); } function createFund() external returns (PeakDeFiFund) { // create fund PeakDeFiFund fund = PeakDeFiFund(createClone(peakdefiFund).toPayable()); fund.initOwner(); // give PeakReward signer rights to fund PeakReward peakReward = PeakReward(peakRewardAddr); peakReward.addSigner(address(fund)); fundCreator[address(fund)] = msg.sender; emit CreateFund(address(fund)); return fund; } function initFund1( PeakDeFiFund fund, string calldata reptokenName, string calldata reptokenSymbol, string calldata sharesName, string calldata sharesSymbol ) external { require( fundCreator[address(fund)] == msg.sender, "PeakDeFiFactory: not creator" ); // create tokens MiniMeToken reptoken = minimeFactory.createCloneToken( address(0), 0, reptokenName, 18, reptokenSymbol, false ); MiniMeToken shares = minimeFactory.createCloneToken( address(0), 0, sharesName, 18, sharesSymbol, true ); MiniMeToken peakReferralToken = minimeFactory.createCloneToken( address(0), 0, "Peak Referral Token", 18, "PRT", false ); // transfer token ownerships to fund reptoken.transferOwnership(address(fund)); shares.transferOwnership(address(fund)); peakReferralToken.transferOwnership(address(fund)); fund.initInternalTokens( address(reptoken), address(shares), address(peakReferralToken) ); } function initFund2( PeakDeFiFund fund, address payable _devFundingAccount, uint256 _devFundingRate, uint256[2] calldata _phaseLengths, address _compoundFactoryAddr ) external { require( fundCreator[address(fund)] == msg.sender, "PeakDeFiFactory: not creator" ); fund.initParams( _devFundingAccount, _phaseLengths, _devFundingRate, address(0), usdcAddr, kyberAddr, _compoundFactoryAddr, peakdefiLogic, peakdefiLogic2, peakdefiLogic3, 1, oneInchAddr, peakRewardAddr, peakStakingAddr ); } function initFund3( PeakDeFiFund fund, uint256 _newManagerRepToken, uint256 _maxNewManagersPerCycle, uint256 _reptokenPrice, uint256 _peakManagerStakeRequired, bool _isPermissioned ) external { require( fundCreator[address(fund)] == msg.sender, "PeakDeFiFactory: not creator" ); fund.initRegistration( _newManagerRepToken, _maxNewManagersPerCycle, _reptokenPrice, _peakManagerStakeRequired, _isPermissioned ); } function initFund4( PeakDeFiFund fund, address[] calldata _kyberTokens, address[] calldata _compoundTokens ) external { require( fundCreator[address(fund)] == msg.sender, "PeakDeFiFactory: not creator" ); fund.initTokenListings(_kyberTokens, _compoundTokens); // deploy and set PeakDeFiProxy PeakDeFiProxy proxy = new PeakDeFiProxy(address(fund)); fund.setProxy(address(proxy).toPayable()); // transfer fund ownership to msg.sender fund.transferOwnership(msg.sender); emit InitFund(address(fund), address(proxy)); } }
pragma solidity 0.5.17; /* Copyright 2016, Jordi Baylina This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ /// @title MiniMeToken Contract /// @author Jordi Baylina /// @dev This token contract's goal is to make it easy for anyone to clone this /// token using the token distribution at a given block, this will allow DAO's /// and DApps to upgrade their features in a decentralized manner without /// affecting the original token /// @dev It is ERC20 compliant, but still needs to under go further testing. import "@openzeppelin/contracts/ownership/Ownable.sol"; import "./TokenController.sol"; contract ApproveAndCallFallBack { function receiveApproval(address from, uint256 _amount, address _token, bytes memory _data) public; } /// @dev The actual token contract, the default owner is the msg.sender /// that deploys the contract, so usually this token will be deployed by a /// token owner contract, which Giveth will call a "Campaign" contract MiniMeToken is Ownable { string public name; //The Token's name: e.g. DigixDAO Tokens uint8 public decimals; //Number of decimals of the smallest unit string public symbol; //An identifier: e.g. REP string public version = "MMT_0.2"; //An arbitrary versioning scheme /// @dev `Checkpoint` is the structure that attaches a block number to a /// given value, the block number attached is the one that last changed the /// value struct Checkpoint { // `fromBlock` is the block number that the value was generated from uint128 fromBlock; // `value` is the amount of tokens at a specific block number uint128 value; } // `parentToken` is the Token address that was cloned to produce this token; // it will be 0x0 for a token that was not cloned MiniMeToken public parentToken; // `parentSnapShotBlock` is the block number from the Parent Token that was // used to determine the initial distribution of the Clone Token uint public parentSnapShotBlock; // `creationBlock` is the block number that the Clone Token was created uint public creationBlock; // `balances` is the map that tracks the balance of each address, in this // contract when the balance changes the block number that the change // occurred is also included in the map mapping (address => Checkpoint[]) balances; // `allowed` tracks any extra transfer rights as in all ERC20 tokens mapping (address => mapping (address => uint256)) allowed; // Tracks the history of the `totalSupply` of the token Checkpoint[] totalSupplyHistory; // Flag that determines if the token is transferable or not. bool public transfersEnabled; // The factory used to create new clone tokens MiniMeTokenFactory public tokenFactory; //////////////// // Constructor //////////////// /// @notice Constructor to create a MiniMeToken /// @param _tokenFactory The address of the MiniMeTokenFactory contract that /// will create the Clone token contracts, the token factory needs to be /// deployed first /// @param _parentToken Address of the parent token, set to 0x0 if it is a /// new token /// @param _parentSnapShotBlock Block of the parent token that will /// determine the initial distribution of the clone token, set to 0 if it /// is a new token /// @param _tokenName Name of the new token /// @param _decimalUnits Number of decimals of the new token /// @param _tokenSymbol Token Symbol for the new token /// @param _transfersEnabled If true, tokens will be able to be transferred constructor( address _tokenFactory, address payable _parentToken, uint _parentSnapShotBlock, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol, bool _transfersEnabled ) public { tokenFactory = MiniMeTokenFactory(_tokenFactory); name = _tokenName; // Set the name decimals = _decimalUnits; // Set the decimals symbol = _tokenSymbol; // Set the symbol parentToken = MiniMeToken(_parentToken); parentSnapShotBlock = _parentSnapShotBlock; transfersEnabled = _transfersEnabled; creationBlock = block.number; } /////////////////// // ERC20 Methods /////////////////// /// @notice Send `_amount` tokens to `_to` from `msg.sender` /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return Whether the transfer was successful or not function transfer(address _to, uint256 _amount) public returns (bool success) { require(transfersEnabled); doTransfer(msg.sender, _to, _amount); return true; } /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it /// is approved by `_from` /// @param _from The address holding the tokens being transferred /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return True if the transfer was successful function transferFrom(address _from, address _to, uint256 _amount ) public returns (bool success) { // The owner of this contract can move tokens around at will, // this is important to recognize! Confirm that you trust the // owner of this contract, which in most situations should be // another open source smart contract or 0x0 if (msg.sender != owner()) { require(transfersEnabled); // The standard ERC 20 transferFrom functionality require(allowed[_from][msg.sender] >= _amount); allowed[_from][msg.sender] -= _amount; } doTransfer(_from, _to, _amount); return true; } /// @dev This is the actual transfer function in the token contract, it can /// only be called by other functions in this contract. /// @param _from The address holding the tokens being transferred /// @param _to The address of the recipient /// @param _amount The amount of tokens to be transferred /// @return True if the transfer was successful function doTransfer(address _from, address _to, uint _amount ) internal { if (_amount == 0) { emit Transfer(_from, _to, _amount); // Follow the spec to louch the event when transfer 0 return; } require(parentSnapShotBlock < block.number); // Do not allow transfer to 0x0 or the token contract itself require((_to != address(0)) && (_to != address(this))); // If the amount being transfered is more than the balance of the // account the transfer throws uint previousBalanceFrom = balanceOfAt(_from, block.number); require(previousBalanceFrom >= _amount); // Alerts the token owner of the transfer if (isContract(owner())) { require(TokenController(owner()).onTransfer(_from, _to, _amount)); } // First update the balance array with the new value for the address // sending the tokens updateValueAtNow(balances[_from], previousBalanceFrom - _amount); // Then update the balance array with the new value for the address // receiving the tokens uint previousBalanceTo = balanceOfAt(_to, block.number); require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow updateValueAtNow(balances[_to], previousBalanceTo + _amount); // An event to make the transfer easy to find on the blockchain emit Transfer(_from, _to, _amount); } /// @param _owner The address that's balance is being requested /// @return The balance of `_owner` at the current block function balanceOf(address _owner) public view returns (uint256 balance) { return balanceOfAt(_owner, block.number); } /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on /// its behalf. This is a modified version of the ERC20 approve function /// to be a little bit safer /// @param _spender The address of the account able to transfer the tokens /// @param _amount The amount of tokens to be approved for transfer /// @return True if the approval was successful function approve(address _spender, uint256 _amount) public returns (bool success) { require(transfersEnabled); // To change the approve amount you first have to reduce the addresses` // allowance to zero by calling `approve(_spender,0)` if it is not // already 0 to mitigate the race condition described here: // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 require((_amount == 0) || (allowed[msg.sender][_spender] == 0)); // Alerts the token owner of the approve function call if (isContract(owner())) { require(TokenController(owner()).onApprove(msg.sender, _spender, _amount)); } allowed[msg.sender][_spender] = _amount; emit Approval(msg.sender, _spender, _amount); return true; } /// @dev This function makes it easy to read the `allowed[]` map /// @param _owner The address of the account that owns the token /// @param _spender The address of the account able to transfer the tokens /// @return Amount of remaining tokens of _owner that _spender is allowed /// to spend function allowance(address _owner, address _spender ) public view returns (uint256 remaining) { return allowed[_owner][_spender]; } /// @notice `msg.sender` approves `_spender` to send `_amount` tokens on /// its behalf, and then a function is triggered in the contract that is /// being approved, `_spender`. This allows users to use their tokens to /// interact with contracts in one function call instead of two /// @param _spender The address of the contract able to transfer the tokens /// @param _amount The amount of tokens to be approved for transfer /// @return True if the function call was successful function approveAndCall(address _spender, uint256 _amount, bytes memory _extraData ) public returns (bool success) { require(approve(_spender, _amount)); ApproveAndCallFallBack(_spender).receiveApproval( msg.sender, _amount, address(this), _extraData ); return true; } /// @dev This function makes it easy to get the total number of tokens /// @return The total number of tokens function totalSupply() public view returns (uint) { return totalSupplyAt(block.number); } //////////////// // Query balance and totalSupply in History //////////////// /// @dev Queries the balance of `_owner` at a specific `_blockNumber` /// @param _owner The address from which the balance will be retrieved /// @param _blockNumber The block number when the balance is queried /// @return The balance at `_blockNumber` function balanceOfAt(address _owner, uint _blockNumber) public view returns (uint) { // These next few lines are used when the balance of the token is // requested before a check point was ever created for this token, it // requires that the `parentToken.balanceOfAt` be queried at the // genesis block for that token as this contains initial balance of // this token if ((balances[_owner].length == 0) || (balances[_owner][0].fromBlock > _blockNumber)) { if (address(parentToken) != address(0)) { return parentToken.balanceOfAt(_owner, min(_blockNumber, parentSnapShotBlock)); } else { // Has no parent return 0; } // This will return the expected balance during normal situations } else { return getValueAt(balances[_owner], _blockNumber); } } /// @notice Total amount of tokens at a specific `_blockNumber`. /// @param _blockNumber The block number when the totalSupply is queried /// @return The total amount of tokens at `_blockNumber` function totalSupplyAt(uint _blockNumber) public view returns(uint) { // These next few lines are used when the totalSupply of the token is // requested before a check point was ever created for this token, it // requires that the `parentToken.totalSupplyAt` be queried at the // genesis block for this token as that contains totalSupply of this // token at this block number. if ((totalSupplyHistory.length == 0) || (totalSupplyHistory[0].fromBlock > _blockNumber)) { if (address(parentToken) != address(0)) { return parentToken.totalSupplyAt(min(_blockNumber, parentSnapShotBlock)); } else { return 0; } // This will return the expected totalSupply during normal situations } else { return getValueAt(totalSupplyHistory, _blockNumber); } } //////////////// // Clone Token Method //////////////// /// @notice Creates a new clone token with the initial distribution being /// this token at `_snapshotBlock` /// @param _cloneTokenName Name of the clone token /// @param _cloneDecimalUnits Number of decimals of the smallest unit /// @param _cloneTokenSymbol Symbol of the clone token /// @param _snapshotBlock Block when the distribution of the parent token is /// copied to set the initial distribution of the new clone token; /// if the block is zero than the actual block, the current block is used /// @param _transfersEnabled True if transfers are allowed in the clone /// @return The address of the new MiniMeToken Contract function createCloneToken( string memory _cloneTokenName, uint8 _cloneDecimalUnits, string memory _cloneTokenSymbol, uint _snapshotBlock, bool _transfersEnabled ) public returns(address) { uint snapshotBlock = _snapshotBlock; if (snapshotBlock == 0) snapshotBlock = block.number; MiniMeToken cloneToken = tokenFactory.createCloneToken( address(this), snapshotBlock, _cloneTokenName, _cloneDecimalUnits, _cloneTokenSymbol, _transfersEnabled ); cloneToken.transferOwnership(msg.sender); // An event to make the token easy to find on the blockchain emit NewCloneToken(address(cloneToken), snapshotBlock); return address(cloneToken); } //////////////// // Generate and destroy tokens //////////////// /// @notice Generates `_amount` tokens that are assigned to `_owner` /// @param _owner The address that will be assigned the new tokens /// @param _amount The quantity of tokens generated /// @return True if the tokens are generated correctly function generateTokens(address _owner, uint _amount ) public onlyOwner returns (bool) { uint curTotalSupply = totalSupply(); require(curTotalSupply + _amount >= curTotalSupply); // Check for overflow uint previousBalanceTo = balanceOf(_owner); require(previousBalanceTo + _amount >= previousBalanceTo); // Check for overflow updateValueAtNow(totalSupplyHistory, curTotalSupply + _amount); updateValueAtNow(balances[_owner], previousBalanceTo + _amount); emit Transfer(address(0), _owner, _amount); return true; } /// @notice Burns `_amount` tokens from `_owner` /// @param _owner The address that will lose the tokens /// @param _amount The quantity of tokens to burn /// @return True if the tokens are burned correctly function destroyTokens(address _owner, uint _amount ) onlyOwner public returns (bool) { uint curTotalSupply = totalSupply(); require(curTotalSupply >= _amount); uint previousBalanceFrom = balanceOf(_owner); require(previousBalanceFrom >= _amount); updateValueAtNow(totalSupplyHistory, curTotalSupply - _amount); updateValueAtNow(balances[_owner], previousBalanceFrom - _amount); emit Transfer(_owner, address(0), _amount); return true; } //////////////// // Enable tokens transfers //////////////// /// @notice Enables token holders to transfer their tokens freely if true /// @param _transfersEnabled True if transfers are allowed in the clone function enableTransfers(bool _transfersEnabled) public onlyOwner { transfersEnabled = _transfersEnabled; } //////////////// // Internal helper functions to query and set a value in a snapshot array //////////////// /// @dev `getValueAt` retrieves the number of tokens at a given block number /// @param checkpoints The history of values being queried /// @param _block The block number to retrieve the value at /// @return The number of tokens being queried function getValueAt(Checkpoint[] storage checkpoints, uint _block ) view internal returns (uint) { if (checkpoints.length == 0) return 0; // Shortcut for the actual value if (_block >= checkpoints[checkpoints.length-1].fromBlock) return checkpoints[checkpoints.length-1].value; if (_block < checkpoints[0].fromBlock) return 0; // Binary search of the value in the array uint min = 0; uint max = checkpoints.length-1; while (max > min) { uint mid = (max + min + 1)/ 2; if (checkpoints[mid].fromBlock<=_block) { min = mid; } else { max = mid-1; } } return checkpoints[min].value; } /// @dev `updateValueAtNow` used to update the `balances` map and the /// `totalSupplyHistory` /// @param checkpoints The history of data being updated /// @param _value The new number of tokens function updateValueAtNow(Checkpoint[] storage checkpoints, uint _value ) internal { if ((checkpoints.length == 0) || (checkpoints[checkpoints.length -1].fromBlock < block.number)) { Checkpoint storage newCheckPoint = checkpoints[ checkpoints.length++ ]; newCheckPoint.fromBlock = uint128(block.number); newCheckPoint.value = uint128(_value); } else { Checkpoint storage oldCheckPoint = checkpoints[checkpoints.length-1]; oldCheckPoint.value = uint128(_value); } } /// @dev Internal function to determine if an address is a contract /// @param _addr The address being queried /// @return True if `_addr` is a contract function isContract(address _addr) view internal returns(bool) { uint size; if (_addr == address(0)) return false; assembly { size := extcodesize(_addr) } return size>0; } /// @dev Helper function to return a min betwen the two uints function min(uint a, uint b) pure internal returns (uint) { return a < b ? a : b; } /// @notice The fallback function: If the contract's owner has not been /// set to 0, then the `proxyPayment` method is called which relays the /// ether and creates tokens as described in the token owner contract function () external payable { require(isContract(owner())); require(TokenController(owner()).proxyPayment.value(msg.value)(msg.sender)); } ////////// // Safety Methods ////////// /// @notice This method can be used by the owner to extract mistakenly /// sent tokens to this contract. /// @param _token The address of the token contract that you want to recover /// set to 0 in case you want to extract ether. function claimTokens(address payable _token) public onlyOwner { if (_token == address(0)) { address(uint160(owner())).transfer(address(this).balance); return; } MiniMeToken token = MiniMeToken(_token); uint balance = token.balanceOf(address(this)); require(token.transfer(owner(), balance)); emit ClaimedTokens(_token, owner(), balance); } //////////////// // Events //////////////// event ClaimedTokens(address indexed _token, address indexed _owner, uint _amount); event Transfer(address indexed _from, address indexed _to, uint256 _amount); event NewCloneToken(address indexed _cloneToken, uint _snapshotBlock); event Approval( address indexed _owner, address indexed _spender, uint256 _amount ); } //////////////// // MiniMeTokenFactory //////////////// /// @dev This contract is used to generate clone contracts from a contract. /// In solidity this is the way to create a contract from a contract of the /// same class contract MiniMeTokenFactory { event CreatedToken(string symbol, address addr); /// @notice Update the DApp by creating a new token with new functionalities /// the msg.sender becomes the owner of this clone token /// @param _parentToken Address of the token being cloned /// @param _snapshotBlock Block of the parent token that will /// determine the initial distribution of the clone token /// @param _tokenName Name of the new token /// @param _decimalUnits Number of decimals of the new token /// @param _tokenSymbol Token Symbol for the new token /// @param _transfersEnabled If true, tokens will be able to be transferred /// @return The address of the new token contract function createCloneToken( address payable _parentToken, uint _snapshotBlock, string memory _tokenName, uint8 _decimalUnits, string memory _tokenSymbol, bool _transfersEnabled ) public returns (MiniMeToken) { MiniMeToken newToken = new MiniMeToken( address(this), _parentToken, _snapshotBlock, _tokenName, _decimalUnits, _tokenSymbol, _transfersEnabled ); newToken.transferOwnership(msg.sender); emit CreatedToken(_tokenSymbol, address(newToken)); return newToken; } }
pragma solidity 0.5.17; /// @dev The token controller contract must implement these functions contract TokenController { /// @notice Called when `_owner` sends ether to the MiniMe Token contract /// @param _owner The address that sent the ether to create tokens /// @return True if the ether is accepted, false if it throws function proxyPayment(address _owner) public payable returns(bool); /// @notice Notifies the controller about a token transfer allowing the /// controller to react if desired /// @param _from The origin of the transfer /// @param _to The destination of the transfer /// @param _amount The amount of the transfer /// @return False if the controller does not authorize the transfer function onTransfer(address _from, address _to, uint _amount) public returns(bool); /// @notice Notifies the controller about an approval allowing the /// controller to react if desired /// @param _owner The address that calls `approve()` /// @param _spender The spender in the `approve()` call /// @param _amount The amount in the `approve()` call /// @return False if the controller does not authorize the approval function onApprove(address _owner, address _spender, uint _amount) public returns(bool); }
pragma solidity 0.5.17; import "./PeakDeFiStorage.sol"; import "./derivatives/CompoundOrderFactory.sol"; /** * @title The main smart contract of the PeakDeFi hedge fund. * @author Zefram Lou (Zebang Liu) */ contract PeakDeFiFund is PeakDeFiStorage, Utils(address(0), address(0), address(0)), TokenController { /** * @notice Passes if the fund is ready for migrating to the next version */ modifier readyForUpgradeMigration { require(hasFinalizedNextVersion == true); require( now > startTimeOfCyclePhase.add( phaseLengths[uint256(CyclePhase.Intermission)] ) ); _; } /** * Meta functions */ function initParams( address payable _devFundingAccount, uint256[2] calldata _phaseLengths, uint256 _devFundingRate, address payable _previousVersion, address _usdcAddr, address payable _kyberAddr, address _compoundFactoryAddr, address _peakdefiLogic, address _peakdefiLogic2, address _peakdefiLogic3, uint256 _startCycleNumber, address payable _oneInchAddr, address _peakRewardAddr, address _peakStakingAddr ) external { require(proxyAddr == address(0)); devFundingAccount = _devFundingAccount; phaseLengths = _phaseLengths; devFundingRate = _devFundingRate; cyclePhase = CyclePhase.Intermission; compoundFactoryAddr = _compoundFactoryAddr; peakdefiLogic = _peakdefiLogic; peakdefiLogic2 = _peakdefiLogic2; peakdefiLogic3 = _peakdefiLogic3; previousVersion = _previousVersion; cycleNumber = _startCycleNumber; peakReward = PeakReward(_peakRewardAddr); peakStaking = PeakStaking(_peakStakingAddr); USDC_ADDR = _usdcAddr; KYBER_ADDR = _kyberAddr; ONEINCH_ADDR = _oneInchAddr; usdc = ERC20Detailed(_usdcAddr); kyber = KyberNetwork(_kyberAddr); __initReentrancyGuard(); } function initOwner() external { require(proxyAddr == address(0)); _transferOwnership(msg.sender); } function initInternalTokens( address payable _repAddr, address payable _sTokenAddr, address payable _peakReferralTokenAddr ) external onlyOwner { require(controlTokenAddr == address(0)); require(_repAddr != address(0)); controlTokenAddr = _repAddr; shareTokenAddr = _sTokenAddr; cToken = IMiniMeToken(_repAddr); sToken = IMiniMeToken(_sTokenAddr); peakReferralToken = IMiniMeToken(_peakReferralTokenAddr); } function initRegistration( uint256 _newManagerRepToken, uint256 _maxNewManagersPerCycle, uint256 _reptokenPrice, uint256 _peakManagerStakeRequired, bool _isPermissioned ) external onlyOwner { require(_newManagerRepToken > 0 && newManagerRepToken == 0); newManagerRepToken = _newManagerRepToken; maxNewManagersPerCycle = _maxNewManagersPerCycle; reptokenPrice = _reptokenPrice; peakManagerStakeRequired = _peakManagerStakeRequired; isPermissioned = _isPermissioned; } function initTokenListings( address[] calldata _kyberTokens, address[] calldata _compoundTokens ) external onlyOwner { // May only initialize once require(!hasInitializedTokenListings); hasInitializedTokenListings = true; uint256 i; for (i = 0; i < _kyberTokens.length; i++) { isKyberToken[_kyberTokens[i]] = true; } CompoundOrderFactory factory = CompoundOrderFactory(compoundFactoryAddr); for (i = 0; i < _compoundTokens.length; i++) { require(factory.tokenIsListed(_compoundTokens[i])); isCompoundToken[_compoundTokens[i]] = true; } } /** * @notice Used during deployment to set the PeakDeFiProxy contract address. * @param _proxyAddr the proxy's address */ function setProxy(address payable _proxyAddr) external onlyOwner { require(_proxyAddr != address(0)); require(proxyAddr == address(0)); proxyAddr = _proxyAddr; proxy = PeakDeFiProxyInterface(_proxyAddr); } /** * Upgrading functions */ /** * @notice Allows the developer to propose a candidate smart contract for the fund to upgrade to. * The developer may change the candidate during the Intermission phase. * @param _candidate the address of the candidate smart contract * @return True if successfully changed candidate, false otherwise. */ function developerInitiateUpgrade(address payable _candidate) public returns (bool _success) { (bool success, bytes memory result) = peakdefiLogic3.delegatecall( abi.encodeWithSelector( this.developerInitiateUpgrade.selector, _candidate ) ); if (!success) { return false; } return abi.decode(result, (bool)); } /** * @notice Transfers ownership of RepToken & Share token contracts to the next version. Also updates PeakDeFiFund's * address in PeakDeFiProxy. */ function migrateOwnedContractsToNextVersion() public nonReentrant readyForUpgradeMigration { cToken.transferOwnership(nextVersion); sToken.transferOwnership(nextVersion); peakReferralToken.transferOwnership(nextVersion); proxy.updatePeakDeFiFundAddress(); } /** * @notice Transfers assets to the next version. * @param _assetAddress the address of the asset to be transferred. Use ETH_TOKEN_ADDRESS to transfer Ether. */ function transferAssetToNextVersion(address _assetAddress) public nonReentrant readyForUpgradeMigration isValidToken(_assetAddress) { if (_assetAddress == address(ETH_TOKEN_ADDRESS)) { nextVersion.transfer(address(this).balance); } else { ERC20Detailed token = ERC20Detailed(_assetAddress); token.safeTransfer(nextVersion, token.balanceOf(address(this))); } } /** * Getters */ /** * @notice Returns the length of the user's investments array. * @return length of the user's investments array */ function investmentsCount(address _userAddr) public view returns (uint256 _count) { return userInvestments[_userAddr].length; } /** * @notice Returns the length of the user's compound orders array. * @return length of the user's compound orders array */ function compoundOrdersCount(address _userAddr) public view returns (uint256 _count) { return userCompoundOrders[_userAddr].length; } /** * @notice Returns the phaseLengths array. * @return the phaseLengths array */ function getPhaseLengths() public view returns (uint256[2] memory _phaseLengths) { return phaseLengths; } /** * @notice Returns the commission balance of `_manager` * @return the commission balance and the received penalty, denoted in USDC */ function commissionBalanceOf(address _manager) public returns (uint256 _commission, uint256 _penalty) { (bool success, bytes memory result) = peakdefiLogic3.delegatecall( abi.encodeWithSelector(this.commissionBalanceOf.selector, _manager) ); if (!success) { return (0, 0); } return abi.decode(result, (uint256, uint256)); } /** * @notice Returns the commission amount received by `_manager` in the `_cycle`th cycle * @return the commission amount and the received penalty, denoted in USDC */ function commissionOfAt(address _manager, uint256 _cycle) public returns (uint256 _commission, uint256 _penalty) { (bool success, bytes memory result) = peakdefiLogic3.delegatecall( abi.encodeWithSelector( this.commissionOfAt.selector, _manager, _cycle ) ); if (!success) { return (0, 0); } return abi.decode(result, (uint256, uint256)); } /** * Parameter setters */ /** * @notice Changes the address to which the developer fees will be sent. Only callable by owner. * @param _newAddr the new developer fee address */ function changeDeveloperFeeAccount(address payable _newAddr) public onlyOwner { require(_newAddr != address(0) && _newAddr != address(this)); devFundingAccount = _newAddr; } /** * @notice Changes the proportion of fund balance sent to the developers each cycle. May only decrease. Only callable by owner. * @param _newProp the new proportion, fixed point decimal */ function changeDeveloperFeeRate(uint256 _newProp) public onlyOwner { require(_newProp < PRECISION); require(_newProp < devFundingRate); devFundingRate = _newProp; } /** * @notice Allows managers to invest in a token. Only callable by owner. * @param _token address of the token to be listed */ function listKyberToken(address _token) public onlyOwner { isKyberToken[_token] = true; } /** * @notice Allows managers to invest in a Compound token. Only callable by owner. * @param _token address of the Compound token to be listed */ function listCompoundToken(address _token) public onlyOwner { CompoundOrderFactory factory = CompoundOrderFactory( compoundFactoryAddr ); require(factory.tokenIsListed(_token)); isCompoundToken[_token] = true; } /** * @notice Moves the fund to the next phase in the investment cycle. */ function nextPhase() public { (bool success, ) = peakdefiLogic3.delegatecall( abi.encodeWithSelector(this.nextPhase.selector) ); if (!success) { revert(); } } /** * Manager registration */ /** * @notice Registers `msg.sender` as a manager, using USDC as payment. The more one pays, the more RepToken one gets. * There's a max RepToken amount that can be bought, and excess payment will be sent back to sender. */ function registerWithUSDC() public { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector(this.registerWithUSDC.selector) ); if (!success) { revert(); } } /** * @notice Registers `msg.sender` as a manager, using ETH as payment. The more one pays, the more RepToken one gets. * There's a max RepToken amount that can be bought, and excess payment will be sent back to sender. */ function registerWithETH() public payable { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector(this.registerWithETH.selector) ); if (!success) { revert(); } } /** * @notice Registers `msg.sender` as a manager, using tokens as payment. The more one pays, the more RepToken one gets. * There's a max RepToken amount that can be bought, and excess payment will be sent back to sender. * @param _token the token to be used for payment * @param _donationInTokens the amount of tokens to be used for registration, should use the token's native decimals */ function registerWithToken(address _token, uint256 _donationInTokens) public { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector( this.registerWithToken.selector, _token, _donationInTokens ) ); if (!success) { revert(); } } /** * Intermission phase functions */ /** * @notice Deposit Ether into the fund. Ether will be converted into USDC. */ function depositEther(address _referrer) public payable { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector(this.depositEther.selector, _referrer) ); if (!success) { revert(); } } function depositEtherAdvanced( bool _useKyber, bytes calldata _calldata, address _referrer ) external payable { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector( this.depositEtherAdvanced.selector, _useKyber, _calldata, _referrer ) ); if (!success) { revert(); } } /** * @notice Deposit USDC Stablecoin into the fund. * @param _usdcAmount The amount of USDC to be deposited. May be different from actual deposited amount. */ function depositUSDC(uint256 _usdcAmount, address _referrer) public { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector( this.depositUSDC.selector, _usdcAmount, _referrer ) ); if (!success) { revert(); } } /** * @notice Deposit ERC20 tokens into the fund. Tokens will be converted into USDC. * @param _tokenAddr the address of the token to be deposited * @param _tokenAmount The amount of tokens to be deposited. May be different from actual deposited amount. */ function depositToken( address _tokenAddr, uint256 _tokenAmount, address _referrer ) public { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector( this.depositToken.selector, _tokenAddr, _tokenAmount, _referrer ) ); if (!success) { revert(); } } function depositTokenAdvanced( address _tokenAddr, uint256 _tokenAmount, bool _useKyber, bytes calldata _calldata, address _referrer ) external { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector( this.depositTokenAdvanced.selector, _tokenAddr, _tokenAmount, _useKyber, _calldata, _referrer ) ); if (!success) { revert(); } } /** * @notice Withdraws Ether by burning Shares. * @param _amountInUSDC Amount of funds to be withdrawn expressed in USDC. Fixed-point decimal. May be different from actual amount. */ function withdrawEther(uint256 _amountInUSDC) external { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector(this.withdrawEther.selector, _amountInUSDC) ); if (!success) { revert(); } } function withdrawEtherAdvanced( uint256 _amountInUSDC, bool _useKyber, bytes calldata _calldata ) external { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector( this.withdrawEtherAdvanced.selector, _amountInUSDC, _useKyber, _calldata ) ); if (!success) { revert(); } } /** * @notice Withdraws Ether by burning Shares. * @param _amountInUSDC Amount of funds to be withdrawn expressed in USDC. Fixed-point decimal. May be different from actual amount. */ function withdrawUSDC(uint256 _amountInUSDC) public { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector(this.withdrawUSDC.selector, _amountInUSDC) ); if (!success) { revert(); } } /** * @notice Withdraws funds by burning Shares, and converts the funds into the specified token using Kyber Network. * @param _tokenAddr the address of the token to be withdrawn into the caller's account * @param _amountInUSDC The amount of funds to be withdrawn expressed in USDC. Fixed-point decimal. May be different from actual amount. */ function withdrawToken(address _tokenAddr, uint256 _amountInUSDC) external { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector( this.withdrawToken.selector, _tokenAddr, _amountInUSDC ) ); if (!success) { revert(); } } function withdrawTokenAdvanced( address _tokenAddr, uint256 _amountInUSDC, bool _useKyber, bytes calldata _calldata ) external { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector( this.withdrawTokenAdvanced.selector, _tokenAddr, _amountInUSDC, _useKyber, _calldata ) ); if (!success) { revert(); } } /** * @notice Redeems commission. */ function redeemCommission(bool _inShares) public { (bool success, ) = peakdefiLogic3.delegatecall( abi.encodeWithSelector(this.redeemCommission.selector, _inShares) ); if (!success) { revert(); } } /** * @notice Redeems commission for a particular cycle. * @param _inShares true to redeem in PeakDeFi Shares, false to redeem in USDC * @param _cycle the cycle for which the commission will be redeemed. * Commissions for a cycle will be redeemed during the Intermission phase of the next cycle, so _cycle must < cycleNumber. */ function redeemCommissionForCycle(bool _inShares, uint256 _cycle) public { (bool success, ) = peakdefiLogic3.delegatecall( abi.encodeWithSelector( this.redeemCommissionForCycle.selector, _inShares, _cycle ) ); if (!success) { revert(); } } /** * @notice Sells tokens left over due to manager not selling or KyberNetwork not having enough volume. Callable by anyone. Money goes to developer. * @param _tokenAddr address of the token to be sold * @param _calldata the 1inch trade call data */ function sellLeftoverToken(address _tokenAddr, bytes calldata _calldata) external { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector( this.sellLeftoverToken.selector, _tokenAddr, _calldata ) ); if (!success) { revert(); } } /** * @notice Sells CompoundOrder left over due to manager not selling or KyberNetwork not having enough volume. Callable by anyone. Money goes to developer. * @param _orderAddress address of the CompoundOrder to be sold */ function sellLeftoverCompoundOrder(address payable _orderAddress) public { (bool success, ) = peakdefiLogic2.delegatecall( abi.encodeWithSelector( this.sellLeftoverCompoundOrder.selector, _orderAddress ) ); if (!success) { revert(); } } /** * @notice Burns the RepToken balance of a manager who has been inactive for a certain number of cycles * @param _deadman the manager whose RepToken balance will be burned */ function burnDeadman(address _deadman) public { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector(this.burnDeadman.selector, _deadman) ); if (!success) { revert(); } } /** * Manage phase functions */ function createInvestmentWithSignature( address _tokenAddress, uint256 _stake, uint256 _maxPrice, bytes calldata _calldata, bool _useKyber, address _manager, uint256 _salt, bytes calldata _signature ) external { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.createInvestmentWithSignature.selector, _tokenAddress, _stake, _maxPrice, _calldata, _useKyber, _manager, _salt, _signature ) ); if (!success) { revert(); } } function sellInvestmentWithSignature( uint256 _investmentId, uint256 _tokenAmount, uint256 _minPrice, uint256 _maxPrice, bytes calldata _calldata, bool _useKyber, address _manager, uint256 _salt, bytes calldata _signature ) external { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.sellInvestmentWithSignature.selector, _investmentId, _tokenAmount, _minPrice, _maxPrice, _calldata, _useKyber, _manager, _salt, _signature ) ); if (!success) { revert(); } } function createCompoundOrderWithSignature( bool _orderType, address _tokenAddress, uint256 _stake, uint256 _minPrice, uint256 _maxPrice, address _manager, uint256 _salt, bytes calldata _signature ) external { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.createCompoundOrderWithSignature.selector, _orderType, _tokenAddress, _stake, _minPrice, _maxPrice, _manager, _salt, _signature ) ); if (!success) { revert(); } } function sellCompoundOrderWithSignature( uint256 _orderId, uint256 _minPrice, uint256 _maxPrice, address _manager, uint256 _salt, bytes calldata _signature ) external { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.sellCompoundOrderWithSignature.selector, _orderId, _minPrice, _maxPrice, _manager, _salt, _signature ) ); if (!success) { revert(); } } function repayCompoundOrderWithSignature( uint256 _orderId, uint256 _repayAmountInUSDC, address _manager, uint256 _salt, bytes calldata _signature ) external { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.repayCompoundOrderWithSignature.selector, _orderId, _repayAmountInUSDC, _manager, _salt, _signature ) ); if (!success) { revert(); } } /** * @notice Creates a new investment for an ERC20 token. * @param _tokenAddress address of the ERC20 token contract * @param _stake amount of RepTokens to be staked in support of the investment * @param _maxPrice the maximum price for the trade */ function createInvestment( address _tokenAddress, uint256 _stake, uint256 _maxPrice ) public { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.createInvestment.selector, _tokenAddress, _stake, _maxPrice ) ); if (!success) { revert(); } } /** * @notice Creates a new investment for an ERC20 token. * @param _tokenAddress address of the ERC20 token contract * @param _stake amount of RepTokens to be staked in support of the investment * @param _maxPrice the maximum price for the trade * @param _calldata calldata for 1inch trading * @param _useKyber true for Kyber Network, false for 1inch */ function createInvestmentV2( address _sender, address _tokenAddress, uint256 _stake, uint256 _maxPrice, bytes memory _calldata, bool _useKyber ) public { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.createInvestmentV2.selector, _sender, _tokenAddress, _stake, _maxPrice, _calldata, _useKyber ) ); if (!success) { revert(); } } /** * @notice Called by user to sell the assets an investment invested in. Returns the staked RepToken plus rewards/penalties to the user. * The user can sell only part of the investment by changing _tokenAmount. * @dev When selling only part of an investment, the old investment would be "fully" sold and a new investment would be created with * the original buy price and however much tokens that are not sold. * @param _investmentId the ID of the investment * @param _tokenAmount the amount of tokens to be sold. * @param _minPrice the minimum price for the trade */ function sellInvestmentAsset( uint256 _investmentId, uint256 _tokenAmount, uint256 _minPrice ) public { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.sellInvestmentAsset.selector, _investmentId, _tokenAmount, _minPrice ) ); if (!success) { revert(); } } /** * @notice Called by user to sell the assets an investment invested in. Returns the staked RepToken plus rewards/penalties to the user. * The user can sell only part of the investment by changing _tokenAmount. * @dev When selling only part of an investment, the old investment would be "fully" sold and a new investment would be created with * the original buy price and however much tokens that are not sold. * @param _investmentId the ID of the investment * @param _tokenAmount the amount of tokens to be sold. * @param _minPrice the minimum price for the trade */ function sellInvestmentAssetV2( address _sender, uint256 _investmentId, uint256 _tokenAmount, uint256 _minPrice, bytes memory _calldata, bool _useKyber ) public { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.sellInvestmentAssetV2.selector, _sender, _investmentId, _tokenAmount, _minPrice, _calldata, _useKyber ) ); if (!success) { revert(); } } /** * @notice Creates a new Compound order to either short or leverage long a token. * @param _orderType true for a short order, false for a levarage long order * @param _tokenAddress address of the Compound token to be traded * @param _stake amount of RepTokens to be staked * @param _minPrice the minimum token price for the trade * @param _maxPrice the maximum token price for the trade */ function createCompoundOrder( address _sender, bool _orderType, address _tokenAddress, uint256 _stake, uint256 _minPrice, uint256 _maxPrice ) public { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.createCompoundOrder.selector, _sender, _orderType, _tokenAddress, _stake, _minPrice, _maxPrice ) ); if (!success) { revert(); } } /** * @notice Sells a compound order * @param _orderId the ID of the order to be sold (index in userCompoundOrders[msg.sender]) * @param _minPrice the minimum token price for the trade * @param _maxPrice the maximum token price for the trade */ function sellCompoundOrder( address _sender, uint256 _orderId, uint256 _minPrice, uint256 _maxPrice ) public { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.sellCompoundOrder.selector, _sender, _orderId, _minPrice, _maxPrice ) ); if (!success) { revert(); } } /** * @notice Repys debt for a Compound order to prevent the collateral ratio from dropping below threshold. * @param _orderId the ID of the Compound order * @param _repayAmountInUSDC amount of USDC to use for repaying debt */ function repayCompoundOrder( address _sender, uint256 _orderId, uint256 _repayAmountInUSDC ) public { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.repayCompoundOrder.selector, _sender, _orderId, _repayAmountInUSDC ) ); if (!success) { revert(); } } /** * @notice Emergency exit the tokens from order contract during intermission stage * @param _sender the address of trader, who created the order * @param _orderId the ID of the Compound order * @param _tokenAddr the address of token which should be transferred * @param _receiver the address of receiver */ function emergencyExitCompoundTokens( address _sender, uint256 _orderId, address _tokenAddr, address _receiver ) public onlyOwner { (bool success, ) = peakdefiLogic.delegatecall( abi.encodeWithSelector( this.emergencyExitCompoundTokens.selector, _sender, _orderId, _tokenAddr, _receiver ) ); if (!success) { revert(); } } /** * Internal use functions */ // MiniMe TokenController functions, not used right now /** * @notice Called when `_owner` sends ether to the MiniMe Token contract * @return True if the ether is accepted, false if it throws */ function proxyPayment( address /*_owner*/ ) public payable returns (bool) { return false; } /** * @notice Notifies the controller about a token transfer allowing the * controller to react if desired * @return False if the controller does not authorize the transfer */ function onTransfer( address, /*_from*/ address, /*_to*/ uint256 /*_amount*/ ) public returns (bool) { return true; } /** * @notice Notifies the controller about an approval allowing the * controller to react if desired * @return False if the controller does not authorize the approval */ function onApprove( address, /*_owner*/ address, /*_spender*/ uint256 /*_amount*/ ) public returns (bool) { return true; } function() external payable {} /** PeakDeFi */ /** * @notice Returns the commission balance of `_referrer` * @return the commission balance and the received penalty, denoted in USDC */ function peakReferralCommissionBalanceOf(address _referrer) public returns (uint256 _commission) { (bool success, bytes memory result) = peakdefiLogic3.delegatecall( abi.encodeWithSelector( this.peakReferralCommissionBalanceOf.selector, _referrer ) ); if (!success) { return 0; } return abi.decode(result, (uint256)); } /** * @notice Returns the commission amount received by `_referrer` in the `_cycle`th cycle * @return the commission amount and the received penalty, denoted in USDC */ function peakReferralCommissionOfAt(address _referrer, uint256 _cycle) public returns (uint256 _commission) { (bool success, bytes memory result) = peakdefiLogic3.delegatecall( abi.encodeWithSelector( this.peakReferralCommissionOfAt.selector, _referrer, _cycle ) ); if (!success) { return 0; } return abi.decode(result, (uint256)); } /** * @notice Redeems commission. */ function peakReferralRedeemCommission() public { (bool success, ) = peakdefiLogic3.delegatecall( abi.encodeWithSelector(this.peakReferralRedeemCommission.selector) ); if (!success) { revert(); } } /** * @notice Redeems commission for a particular cycle. * @param _cycle the cycle for which the commission will be redeemed. * Commissions for a cycle will be redeemed during the Intermission phase of the next cycle, so _cycle must < cycleNumber. */ function peakReferralRedeemCommissionForCycle(uint256 _cycle) public { (bool success, ) = peakdefiLogic3.delegatecall( abi.encodeWithSelector( this.peakReferralRedeemCommissionForCycle.selector, _cycle ) ); if (!success) { revert(); } } /** * @notice Changes the required PEAK stake of a new manager. Only callable by owner. * @param _newValue the new value */ function peakChangeManagerStakeRequired(uint256 _newValue) public onlyOwner { peakManagerStakeRequired = _newValue; } }
pragma solidity 0.5.17; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/ownership/Ownable.sol"; import "./lib/ReentrancyGuard.sol"; import "./interfaces/IMiniMeToken.sol"; import "./tokens/minime/TokenController.sol"; import "./Utils.sol"; import "./PeakDeFiProxyInterface.sol"; import "./peak/reward/PeakReward.sol"; import "./peak/staking/PeakStaking.sol"; /** * @title The storage layout of PeakDeFiFund * @author Zefram Lou (Zebang Liu) */ contract PeakDeFiStorage is Ownable, ReentrancyGuard { using SafeMath for uint256; enum CyclePhase {Intermission, Manage} enum VoteDirection {Empty, For, Against} enum Subchunk {Propose, Vote} struct Investment { address tokenAddress; uint256 cycleNumber; uint256 stake; uint256 tokenAmount; uint256 buyPrice; // token buy price in 18 decimals in USDC uint256 sellPrice; // token sell price in 18 decimals in USDC uint256 buyTime; uint256 buyCostInUSDC; bool isSold; } // Fund parameters uint256 public constant COMMISSION_RATE = 15 * (10**16); // The proportion of profits that gets distributed to RepToken holders every cycle. uint256 public constant ASSET_FEE_RATE = 1 * (10**15); // The proportion of fund balance that gets distributed to RepToken holders every cycle. uint256 public constant NEXT_PHASE_REWARD = 1 * (10**18); // Amount of RepToken rewarded to the user who calls nextPhase(). uint256 public constant COLLATERAL_RATIO_MODIFIER = 75 * (10**16); // Modifies Compound's collateral ratio, gets 2:1 from 1.5:1 ratio uint256 public constant MIN_RISK_TIME = 3 days; // Mininum risk taken to get full commissions is 9 days * reptokenBalance uint256 public constant INACTIVE_THRESHOLD = 2; // Number of inactive cycles after which a manager's RepToken balance can be burned uint256 public constant ROI_PUNISH_THRESHOLD = 1 * (10**17); // ROI worse than 10% will see punishment in stake uint256 public constant ROI_BURN_THRESHOLD = 25 * (10**16); // ROI worse than 25% will see their stake all burned uint256 public constant ROI_PUNISH_SLOPE = 6; // repROI = -(6 * absROI - 0.5) uint256 public constant ROI_PUNISH_NEG_BIAS = 5 * (10**17); // repROI = -(6 * absROI - 0.5) uint256 public constant PEAK_COMMISSION_RATE = 20 * (10**16); // The proportion of profits that gets distributed to PeakDeFi referrers every cycle. // Instance variables // Checks if the token listing initialization has been completed. bool public hasInitializedTokenListings; // Checks if the fund has been initialized bool public isInitialized; // Address of the RepToken token contract. address public controlTokenAddr; // Address of the share token contract. address public shareTokenAddr; // Address of the PeakDeFiProxy contract. address payable public proxyAddr; // Address of the CompoundOrderFactory contract. address public compoundFactoryAddr; // Address of the PeakDeFiLogic contract. address public peakdefiLogic; address public peakdefiLogic2; address public peakdefiLogic3; // Address to which the development team funding will be sent. address payable public devFundingAccount; // Address of the previous version of PeakDeFiFund. address payable public previousVersion; // The number of the current investment cycle. uint256 public cycleNumber; // The amount of funds held by the fund. uint256 public totalFundsInUSDC; // The total funds at the beginning of the current management phase uint256 public totalFundsAtManagePhaseStart; // The start time for the current investment cycle phase, in seconds since Unix epoch. uint256 public startTimeOfCyclePhase; // The proportion of PeakDeFi Shares total supply to mint and use for funding the development team. Fixed point decimal. uint256 public devFundingRate; // Total amount of commission unclaimed by managers uint256 public totalCommissionLeft; // Stores the lengths of each cycle phase in seconds. uint256[2] public phaseLengths; // The number of managers onboarded during the current cycle uint256 public managersOnboardedThisCycle; // The amount of RepToken tokens a new manager receves uint256 public newManagerRepToken; // The max number of new managers that can be onboarded in one cycle uint256 public maxNewManagersPerCycle; // The price of RepToken in USDC uint256 public reptokenPrice; // The last cycle where a user redeemed all of their remaining commission. mapping(address => uint256) internal _lastCommissionRedemption; // Marks whether a manager has redeemed their commission for a certain cycle mapping(address => mapping(uint256 => bool)) internal _hasRedeemedCommissionForCycle; // The stake-time measured risk that a manager has taken in a cycle mapping(address => mapping(uint256 => uint256)) internal _riskTakenInCycle; // In case a manager joined the fund during the current cycle, set the fallback base stake for risk threshold calculation mapping(address => uint256) internal _baseRiskStakeFallback; // List of investments of a manager in the current cycle. mapping(address => Investment[]) public userInvestments; // List of short/long orders of a manager in the current cycle. mapping(address => address payable[]) public userCompoundOrders; // Total commission to be paid for work done in a certain cycle (will be redeemed in the next cycle's Intermission) mapping(uint256 => uint256) internal _totalCommissionOfCycle; // The block number at which the Manage phase ended for a given cycle mapping(uint256 => uint256) internal _managePhaseEndBlock; // The last cycle where a manager made an investment mapping(address => uint256) internal _lastActiveCycle; // Checks if an address points to a whitelisted Kyber token. mapping(address => bool) public isKyberToken; // Checks if an address points to a whitelisted Compound token. Returns false for cUSDC and other stablecoin CompoundTokens. mapping(address => bool) public isCompoundToken; // The current cycle phase. CyclePhase public cyclePhase; // Upgrade governance related variables bool public hasFinalizedNextVersion; // Denotes if the address of the next smart contract version has been finalized address payable public nextVersion; // Address of the next version of PeakDeFiFund. // Contract instances IMiniMeToken internal cToken; IMiniMeToken internal sToken; PeakDeFiProxyInterface internal proxy; // PeakDeFi uint256 public peakReferralTotalCommissionLeft; uint256 public peakManagerStakeRequired; mapping(uint256 => uint256) internal _peakReferralTotalCommissionOfCycle; mapping(address => uint256) internal _peakReferralLastCommissionRedemption; mapping(address => mapping(uint256 => bool)) internal _peakReferralHasRedeemedCommissionForCycle; IMiniMeToken public peakReferralToken; PeakReward public peakReward; PeakStaking public peakStaking; bool public isPermissioned; mapping(address => mapping(uint256 => bool)) public hasUsedSalt; // Events event ChangedPhase( uint256 indexed _cycleNumber, uint256 indexed _newPhase, uint256 _timestamp, uint256 _totalFundsInUSDC ); event Deposit( uint256 indexed _cycleNumber, address indexed _sender, address _tokenAddress, uint256 _tokenAmount, uint256 _usdcAmount, uint256 _timestamp ); event Withdraw( uint256 indexed _cycleNumber, address indexed _sender, address _tokenAddress, uint256 _tokenAmount, uint256 _usdcAmount, uint256 _timestamp ); event CreatedInvestment( uint256 indexed _cycleNumber, address indexed _sender, uint256 _id, address _tokenAddress, uint256 _stakeInWeis, uint256 _buyPrice, uint256 _costUSDCAmount, uint256 _tokenAmount ); event SoldInvestment( uint256 indexed _cycleNumber, address indexed _sender, uint256 _id, address _tokenAddress, uint256 _receivedRepToken, uint256 _sellPrice, uint256 _earnedUSDCAmount ); event CreatedCompoundOrder( uint256 indexed _cycleNumber, address indexed _sender, uint256 _id, address _order, bool _orderType, address _tokenAddress, uint256 _stakeInWeis, uint256 _costUSDCAmount ); event SoldCompoundOrder( uint256 indexed _cycleNumber, address indexed _sender, uint256 _id, address _order, bool _orderType, address _tokenAddress, uint256 _receivedRepToken, uint256 _earnedUSDCAmount ); event RepaidCompoundOrder( uint256 indexed _cycleNumber, address indexed _sender, uint256 _id, address _order, uint256 _repaidUSDCAmount ); event CommissionPaid( uint256 indexed _cycleNumber, address indexed _sender, uint256 _commission ); event TotalCommissionPaid( uint256 indexed _cycleNumber, uint256 _totalCommissionInUSDC ); event Register( address indexed _manager, uint256 _donationInUSDC, uint256 _reptokenReceived ); event BurnDeadman(address indexed _manager, uint256 _reptokenBurned); event DeveloperInitiatedUpgrade( uint256 indexed _cycleNumber, address _candidate ); event FinalizedNextVersion( uint256 indexed _cycleNumber, address _nextVersion ); event PeakReferralCommissionPaid( uint256 indexed _cycleNumber, address indexed _sender, uint256 _commission ); event PeakReferralTotalCommissionPaid( uint256 indexed _cycleNumber, uint256 _totalCommissionInUSDC ); /* Helper functions shared by both PeakDeFiLogic & PeakDeFiFund */ function lastCommissionRedemption(address _manager) public view returns (uint256) { if (_lastCommissionRedemption[_manager] == 0) { return previousVersion == address(0) ? 0 : PeakDeFiStorage(previousVersion).lastCommissionRedemption( _manager ); } return _lastCommissionRedemption[_manager]; } function hasRedeemedCommissionForCycle(address _manager, uint256 _cycle) public view returns (bool) { if (_hasRedeemedCommissionForCycle[_manager][_cycle] == false) { return previousVersion == address(0) ? false : PeakDeFiStorage(previousVersion) .hasRedeemedCommissionForCycle(_manager, _cycle); } return _hasRedeemedCommissionForCycle[_manager][_cycle]; } function riskTakenInCycle(address _manager, uint256 _cycle) public view returns (uint256) { if (_riskTakenInCycle[_manager][_cycle] == 0) { return previousVersion == address(0) ? 0 : PeakDeFiStorage(previousVersion).riskTakenInCycle( _manager, _cycle ); } return _riskTakenInCycle[_manager][_cycle]; } function baseRiskStakeFallback(address _manager) public view returns (uint256) { if (_baseRiskStakeFallback[_manager] == 0) { return previousVersion == address(0) ? 0 : PeakDeFiStorage(previousVersion).baseRiskStakeFallback( _manager ); } return _baseRiskStakeFallback[_manager]; } function totalCommissionOfCycle(uint256 _cycle) public view returns (uint256) { if (_totalCommissionOfCycle[_cycle] == 0) { return previousVersion == address(0) ? 0 : PeakDeFiStorage(previousVersion).totalCommissionOfCycle( _cycle ); } return _totalCommissionOfCycle[_cycle]; } function managePhaseEndBlock(uint256 _cycle) public view returns (uint256) { if (_managePhaseEndBlock[_cycle] == 0) { return previousVersion == address(0) ? 0 : PeakDeFiStorage(previousVersion).managePhaseEndBlock( _cycle ); } return _managePhaseEndBlock[_cycle]; } function lastActiveCycle(address _manager) public view returns (uint256) { if (_lastActiveCycle[_manager] == 0) { return previousVersion == address(0) ? 0 : PeakDeFiStorage(previousVersion).lastActiveCycle(_manager); } return _lastActiveCycle[_manager]; } /** PeakDeFi */ function peakReferralLastCommissionRedemption(address _manager) public view returns (uint256) { if (_peakReferralLastCommissionRedemption[_manager] == 0) { return previousVersion == address(0) ? 0 : PeakDeFiStorage(previousVersion) .peakReferralLastCommissionRedemption(_manager); } return _peakReferralLastCommissionRedemption[_manager]; } function peakReferralHasRedeemedCommissionForCycle( address _manager, uint256 _cycle ) public view returns (bool) { if ( _peakReferralHasRedeemedCommissionForCycle[_manager][_cycle] == false ) { return previousVersion == address(0) ? false : PeakDeFiStorage(previousVersion) .peakReferralHasRedeemedCommissionForCycle( _manager, _cycle ); } return _peakReferralHasRedeemedCommissionForCycle[_manager][_cycle]; } function peakReferralTotalCommissionOfCycle(uint256 _cycle) public view returns (uint256) { if (_peakReferralTotalCommissionOfCycle[_cycle] == 0) { return previousVersion == address(0) ? 0 : PeakDeFiStorage(previousVersion) .peakReferralTotalCommissionOfCycle(_cycle); } return _peakReferralTotalCommissionOfCycle[_cycle]; } }
pragma solidity 0.5.17; interface PeakDeFiProxyInterface { function peakdefiFundAddress() external view returns (address payable); function updatePeakDeFiFundAddress() external; }
pragma solidity 0.5.17; import "./PeakDeFiFund.sol"; contract PeakDeFiProxy { address payable public peakdefiFundAddress; event UpdatedFundAddress(address payable _newFundAddr); constructor(address payable _fundAddr) public { peakdefiFundAddress = _fundAddr; emit UpdatedFundAddress(_fundAddr); } function updatePeakDeFiFundAddress() public { require(msg.sender == peakdefiFundAddress, "Sender not PeakDeFiFund"); address payable nextVersion = PeakDeFiFund(peakdefiFundAddress) .nextVersion(); require(nextVersion != address(0), "Next version can't be empty"); peakdefiFundAddress = nextVersion; emit UpdatedFundAddress(peakdefiFundAddress); } }
pragma solidity 0.5.17; import "@openzeppelin/contracts/cryptography/ECDSA.sol"; import "./PeakDeFiStorage.sol"; import "./derivatives/CompoundOrderFactory.sol"; /** * @title Part of the functions for PeakDeFiFund * @author Zefram Lou (Zebang Liu) */ contract PeakDeFiLogic is PeakDeFiStorage, Utils(address(0), address(0), address(0)) { /** * @notice Executes function only during the given cycle phase. * @param phase the cycle phase during which the function may be called */ modifier during(CyclePhase phase) { require(cyclePhase == phase); if (cyclePhase == CyclePhase.Intermission) { require(isInitialized); } _; } /** * @notice Returns the length of the user's investments array. * @return length of the user's investments array */ function investmentsCount(address _userAddr) public view returns (uint256 _count) { return userInvestments[_userAddr].length; } /** * @notice Burns the RepToken balance of a manager who has been inactive for a certain number of cycles * @param _deadman the manager whose RepToken balance will be burned */ function burnDeadman(address _deadman) public nonReentrant during(CyclePhase.Intermission) { require(_deadman != address(this)); require( cycleNumber.sub(lastActiveCycle(_deadman)) > INACTIVE_THRESHOLD ); uint256 balance = cToken.balanceOf(_deadman); require(cToken.destroyTokens(_deadman, balance)); emit BurnDeadman(_deadman, balance); } /** * @notice Creates a new investment for an ERC20 token. Backwards compatible. * @param _tokenAddress address of the ERC20 token contract * @param _stake amount of RepTokens to be staked in support of the investment * @param _maxPrice the maximum price for the trade */ function createInvestment( address _tokenAddress, uint256 _stake, uint256 _maxPrice ) public { bytes memory nil; createInvestmentV2( msg.sender, _tokenAddress, _stake, _maxPrice, nil, true ); } function createInvestmentWithSignature( address _tokenAddress, uint256 _stake, uint256 _maxPrice, bytes calldata _calldata, bool _useKyber, address _manager, uint256 _salt, bytes calldata _signature ) external { require(!hasUsedSalt[_manager][_salt]); bytes32 naiveHash = keccak256( abi.encodeWithSelector( this.createInvestmentWithSignature.selector, abi.encode( _tokenAddress, _stake, _maxPrice, _calldata, _useKyber ), "|END|", _salt, address(this) ) ); bytes32 msgHash = ECDSA.toEthSignedMessageHash(naiveHash); address recoveredAddress = ECDSA.recover(msgHash, _signature); require(recoveredAddress == _manager); // Signature valid, record use of salt hasUsedSalt[_manager][_salt] = true; this.createInvestmentV2( _manager, _tokenAddress, _stake, _maxPrice, _calldata, _useKyber ); } /** * @notice Called by user to sell the assets an investment invested in. Returns the staked RepToken plus rewards/penalties to the user. * The user can sell only part of the investment by changing _tokenAmount. Backwards compatible. * @dev When selling only part of an investment, the old investment would be "fully" sold and a new investment would be created with * the original buy price and however much tokens that are not sold. * @param _investmentId the ID of the investment * @param _tokenAmount the amount of tokens to be sold. * @param _minPrice the minimum price for the trade */ function sellInvestmentAsset( uint256 _investmentId, uint256 _tokenAmount, uint256 _minPrice ) public { bytes memory nil; sellInvestmentAssetV2( msg.sender, _investmentId, _tokenAmount, _minPrice, nil, true ); } function sellInvestmentWithSignature( uint256 _investmentId, uint256 _tokenAmount, uint256 _minPrice, bytes calldata _calldata, bool _useKyber, address _manager, uint256 _salt, bytes calldata _signature ) external { require(!hasUsedSalt[_manager][_salt]); bytes32 naiveHash = keccak256( abi.encodeWithSelector( this.sellInvestmentWithSignature.selector, abi.encode( _investmentId, _tokenAmount, _minPrice, _calldata, _useKyber ), "|END|", _salt, address(this) ) ); bytes32 msgHash = ECDSA.toEthSignedMessageHash(naiveHash); address recoveredAddress = ECDSA.recover(msgHash, _signature); require(recoveredAddress == _manager); // Signature valid, record use of salt hasUsedSalt[_manager][_salt] = true; this.sellInvestmentAssetV2( _manager, _investmentId, _tokenAmount, _minPrice, _calldata, _useKyber ); } /** * @notice Creates a new investment for an ERC20 token. * @param _tokenAddress address of the ERC20 token contract * @param _stake amount of RepTokens to be staked in support of the investment * @param _maxPrice the maximum price for the trade * @param _calldata calldata for 1inch trading * @param _useKyber true for Kyber Network, false for 1inch */ function createInvestmentV2( address _sender, address _tokenAddress, uint256 _stake, uint256 _maxPrice, bytes memory _calldata, bool _useKyber ) public during(CyclePhase.Manage) nonReentrant isValidToken(_tokenAddress) { require(msg.sender == _sender || msg.sender == address(this)); require(_stake > 0); require(isKyberToken[_tokenAddress]); // Verify user peak stake uint256 peakStake = peakStaking.userStakeAmount(_sender); require(peakStake >= peakManagerStakeRequired); // Collect stake require(cToken.generateTokens(address(this), _stake)); require(cToken.destroyTokens(_sender, _stake)); // Add investment to list userInvestments[_sender].push( Investment({ tokenAddress: _tokenAddress, cycleNumber: cycleNumber, stake: _stake, tokenAmount: 0, buyPrice: 0, sellPrice: 0, buyTime: now, buyCostInUSDC: 0, isSold: false }) ); // Invest uint256 investmentId = investmentsCount(_sender).sub(1); __handleInvestment( _sender, investmentId, 0, _maxPrice, true, _calldata, _useKyber ); // Update last active cycle _lastActiveCycle[_sender] = cycleNumber; // Emit event __emitCreatedInvestmentEvent(_sender, investmentId); } /** * @notice Called by user to sell the assets an investment invested in. Returns the staked RepToken plus rewards/penalties to the user. * The user can sell only part of the investment by changing _tokenAmount. * @dev When selling only part of an investment, the old investment would be "fully" sold and a new investment would be created with * the original buy price and however much tokens that are not sold. * @param _investmentId the ID of the investment * @param _tokenAmount the amount of tokens to be sold. * @param _minPrice the minimum price for the trade */ function sellInvestmentAssetV2( address _sender, uint256 _investmentId, uint256 _tokenAmount, uint256 _minPrice, bytes memory _calldata, bool _useKyber ) public nonReentrant during(CyclePhase.Manage) { require(msg.sender == _sender || msg.sender == address(this)); Investment storage investment = userInvestments[_sender][_investmentId]; require( investment.buyPrice > 0 && investment.cycleNumber == cycleNumber && !investment.isSold ); require(_tokenAmount > 0 && _tokenAmount <= investment.tokenAmount); // Create new investment for leftover tokens bool isPartialSell = false; uint256 stakeOfSoldTokens = investment.stake.mul(_tokenAmount).div( investment.tokenAmount ); if (_tokenAmount != investment.tokenAmount) { isPartialSell = true; __createInvestmentForLeftovers( _sender, _investmentId, _tokenAmount ); __emitCreatedInvestmentEvent( _sender, investmentsCount(_sender).sub(1) ); } // Update investment info investment.isSold = true; // Sell asset ( uint256 actualDestAmount, uint256 actualSrcAmount ) = __handleInvestment( _sender, _investmentId, _minPrice, uint256(-1), false, _calldata, _useKyber ); __sellInvestmentUpdate( _sender, _investmentId, stakeOfSoldTokens, actualDestAmount ); } function __sellInvestmentUpdate( address _sender, uint256 _investmentId, uint256 stakeOfSoldTokens, uint256 actualDestAmount ) internal { Investment storage investment = userInvestments[_sender][_investmentId]; // Return staked RepToken uint256 receiveRepTokenAmount = getReceiveRepTokenAmount( stakeOfSoldTokens, investment.sellPrice, investment.buyPrice ); __returnStake(receiveRepTokenAmount, stakeOfSoldTokens); // Record risk taken in investment __recordRisk(_sender, investment.stake, investment.buyTime); // Update total funds totalFundsInUSDC = totalFundsInUSDC.sub(investment.buyCostInUSDC).add( actualDestAmount ); // Emit event __emitSoldInvestmentEvent( _sender, _investmentId, receiveRepTokenAmount, actualDestAmount ); } function __emitSoldInvestmentEvent( address _sender, uint256 _investmentId, uint256 _receiveRepTokenAmount, uint256 _actualDestAmount ) internal { Investment storage investment = userInvestments[_sender][_investmentId]; emit SoldInvestment( cycleNumber, _sender, _investmentId, investment.tokenAddress, _receiveRepTokenAmount, investment.sellPrice, _actualDestAmount ); } function __createInvestmentForLeftovers( address _sender, uint256 _investmentId, uint256 _tokenAmount ) internal { Investment storage investment = userInvestments[_sender][_investmentId]; uint256 stakeOfSoldTokens = investment.stake.mul(_tokenAmount).div( investment.tokenAmount ); // calculate the part of original USDC cost attributed to the sold tokens uint256 soldBuyCostInUSDC = investment .buyCostInUSDC .mul(_tokenAmount) .div(investment.tokenAmount); userInvestments[_sender].push( Investment({ tokenAddress: investment.tokenAddress, cycleNumber: cycleNumber, stake: investment.stake.sub(stakeOfSoldTokens), tokenAmount: investment.tokenAmount.sub(_tokenAmount), buyPrice: investment.buyPrice, sellPrice: 0, buyTime: investment.buyTime, buyCostInUSDC: investment.buyCostInUSDC.sub(soldBuyCostInUSDC), isSold: false }) ); // update the investment object being sold investment.tokenAmount = _tokenAmount; investment.stake = stakeOfSoldTokens; investment.buyCostInUSDC = soldBuyCostInUSDC; } function __emitCreatedInvestmentEvent(address _sender, uint256 _id) internal { Investment storage investment = userInvestments[_sender][_id]; emit CreatedInvestment( cycleNumber, _sender, _id, investment.tokenAddress, investment.stake, investment.buyPrice, investment.buyCostInUSDC, investment.tokenAmount ); } function createCompoundOrderWithSignature( bool _orderType, address _tokenAddress, uint256 _stake, uint256 _minPrice, uint256 _maxPrice, address _manager, uint256 _salt, bytes calldata _signature ) external { require(!hasUsedSalt[_manager][_salt]); bytes32 naiveHash = keccak256( abi.encodeWithSelector( this.createCompoundOrderWithSignature.selector, abi.encode( _orderType, _tokenAddress, _stake, _minPrice, _maxPrice ), "|END|", _salt, address(this) ) ); bytes32 msgHash = ECDSA.toEthSignedMessageHash(naiveHash); address recoveredAddress = ECDSA.recover(msgHash, _signature); require(recoveredAddress == _manager); // Signature valid, record use of salt hasUsedSalt[_manager][_salt] = true; this.createCompoundOrder( _manager, _orderType, _tokenAddress, _stake, _minPrice, _maxPrice ); } function sellCompoundOrderWithSignature( uint256 _orderId, uint256 _minPrice, uint256 _maxPrice, address _manager, uint256 _salt, bytes calldata _signature ) external { require(!hasUsedSalt[_manager][_salt]); bytes32 naiveHash = keccak256( abi.encodeWithSelector( this.sellCompoundOrderWithSignature.selector, abi.encode(_orderId, _minPrice, _maxPrice), "|END|", _salt, address(this) ) ); bytes32 msgHash = ECDSA.toEthSignedMessageHash(naiveHash); address recoveredAddress = ECDSA.recover(msgHash, _signature); require(recoveredAddress == _manager); // Signature valid, record use of salt hasUsedSalt[_manager][_salt] = true; this.sellCompoundOrder(_manager, _orderId, _minPrice, _maxPrice); } function repayCompoundOrderWithSignature( uint256 _orderId, uint256 _repayAmountInUSDC, address _manager, uint256 _salt, bytes calldata _signature ) external { require(!hasUsedSalt[_manager][_salt]); bytes32 naiveHash = keccak256( abi.encodeWithSelector( this.repayCompoundOrderWithSignature.selector, abi.encode(_orderId, _repayAmountInUSDC), "|END|", _salt, address(this) ) ); bytes32 msgHash = ECDSA.toEthSignedMessageHash(naiveHash); address recoveredAddress = ECDSA.recover(msgHash, _signature); require(recoveredAddress == _manager); // Signature valid, record use of salt hasUsedSalt[_manager][_salt] = true; this.repayCompoundOrder(_manager, _orderId, _repayAmountInUSDC); } /** * @notice Creates a new Compound order to either short or leverage long a token. * @param _orderType true for a short order, false for a levarage long order * @param _tokenAddress address of the Compound token to be traded * @param _stake amount of RepTokens to be staked * @param _minPrice the minimum token price for the trade * @param _maxPrice the maximum token price for the trade */ function createCompoundOrder( address _sender, bool _orderType, address _tokenAddress, uint256 _stake, uint256 _minPrice, uint256 _maxPrice ) public during(CyclePhase.Manage) nonReentrant isValidToken(_tokenAddress) { require(msg.sender == _sender || msg.sender == address(this)); require(_minPrice <= _maxPrice); require(_stake > 0); require(isCompoundToken[_tokenAddress]); // Verify user peak stake uint256 peakStake = peakStaking.userStakeAmount(_sender); require(peakStake >= peakManagerStakeRequired); // Collect stake require(cToken.generateTokens(address(this), _stake)); require(cToken.destroyTokens(_sender, _stake)); // Create compound order and execute uint256 collateralAmountInUSDC = totalFundsInUSDC.mul(_stake).div( cToken.totalSupply() ); CompoundOrder order = __createCompoundOrder( _orderType, _tokenAddress, _stake, collateralAmountInUSDC ); usdc.safeApprove(address(order), 0); usdc.safeApprove(address(order), collateralAmountInUSDC); order.executeOrder(_minPrice, _maxPrice); // Add order to list userCompoundOrders[_sender].push(address(order)); // Update last active cycle _lastActiveCycle[_sender] = cycleNumber; __emitCreatedCompoundOrderEvent( _sender, address(order), _orderType, _tokenAddress, _stake, collateralAmountInUSDC ); } function __emitCreatedCompoundOrderEvent( address _sender, address order, bool _orderType, address _tokenAddress, uint256 _stake, uint256 collateralAmountInUSDC ) internal { // Emit event emit CreatedCompoundOrder( cycleNumber, _sender, userCompoundOrders[_sender].length - 1, address(order), _orderType, _tokenAddress, _stake, collateralAmountInUSDC ); } /** * @notice Sells a compound order * @param _orderId the ID of the order to be sold (index in userCompoundOrders[msg.sender]) * @param _minPrice the minimum token price for the trade * @param _maxPrice the maximum token price for the trade */ function sellCompoundOrder( address _sender, uint256 _orderId, uint256 _minPrice, uint256 _maxPrice ) public during(CyclePhase.Manage) nonReentrant { require(msg.sender == _sender || msg.sender == address(this)); // Load order info require(userCompoundOrders[_sender][_orderId] != address(0)); CompoundOrder order = CompoundOrder( userCompoundOrders[_sender][_orderId] ); require(order.isSold() == false && order.cycleNumber() == cycleNumber); // Sell order (uint256 inputAmount, uint256 outputAmount) = order.sellOrder( _minPrice, _maxPrice ); // Return staked RepToken uint256 stake = order.stake(); uint256 receiveRepTokenAmount = getReceiveRepTokenAmount( stake, outputAmount, inputAmount ); __returnStake(receiveRepTokenAmount, stake); // Record risk taken __recordRisk(_sender, stake, order.buyTime()); // Update total funds totalFundsInUSDC = totalFundsInUSDC.sub(inputAmount).add(outputAmount); // Emit event emit SoldCompoundOrder( cycleNumber, _sender, userCompoundOrders[_sender].length - 1, address(order), order.orderType(), order.compoundTokenAddr(), receiveRepTokenAmount, outputAmount ); } /** * @notice Repys debt for a Compound order to prevent the collateral ratio from dropping below threshold. * @param _orderId the ID of the Compound order * @param _repayAmountInUSDC amount of USDC to use for repaying debt */ function repayCompoundOrder( address _sender, uint256 _orderId, uint256 _repayAmountInUSDC ) public during(CyclePhase.Manage) nonReentrant { require(msg.sender == _sender || msg.sender == address(this)); // Load order info require(userCompoundOrders[_sender][_orderId] != address(0)); CompoundOrder order = CompoundOrder( userCompoundOrders[_sender][_orderId] ); require(order.isSold() == false && order.cycleNumber() == cycleNumber); // Repay loan order.repayLoan(_repayAmountInUSDC); // Emit event emit RepaidCompoundOrder( cycleNumber, _sender, userCompoundOrders[_sender].length - 1, address(order), _repayAmountInUSDC ); } function emergencyExitCompoundTokens( address _sender, uint256 _orderId, address _tokenAddr, address _receiver ) public during(CyclePhase.Intermission) nonReentrant { CompoundOrder order = CompoundOrder(userCompoundOrders[_sender][_orderId]); order.emergencyExitTokens(_tokenAddr, _receiver); } function getReceiveRepTokenAmount( uint256 stake, uint256 output, uint256 input ) public pure returns (uint256 _amount) { if (output >= input) { // positive ROI, simply return stake * (1 + ROI) return stake.mul(output).div(input); } else { // negative ROI uint256 absROI = input.sub(output).mul(PRECISION).div(input); if (absROI <= ROI_PUNISH_THRESHOLD) { // ROI better than -10%, no punishment return stake.mul(output).div(input); } else if ( absROI > ROI_PUNISH_THRESHOLD && absROI < ROI_BURN_THRESHOLD ) { // ROI between -10% and -25%, punish // return stake * (1 + roiWithPunishment) = stake * (1 + (-(6 * absROI - 0.5))) return stake .mul( PRECISION.sub( ROI_PUNISH_SLOPE.mul(absROI).sub( ROI_PUNISH_NEG_BIAS ) ) ) .div(PRECISION); } else { // ROI greater than 25%, burn all stake return 0; } } } /** * @notice Handles and investment by doing the necessary trades using __kyberTrade() or Fulcrum trading * @param _investmentId the ID of the investment to be handled * @param _minPrice the minimum price for the trade * @param _maxPrice the maximum price for the trade * @param _buy whether to buy or sell the given investment * @param _calldata calldata for 1inch trading * @param _useKyber true for Kyber Network, false for 1inch */ function __handleInvestment( address _sender, uint256 _investmentId, uint256 _minPrice, uint256 _maxPrice, bool _buy, bytes memory _calldata, bool _useKyber ) internal returns (uint256 _actualDestAmount, uint256 _actualSrcAmount) { Investment storage investment = userInvestments[_sender][_investmentId]; address token = investment.tokenAddress; // Basic trading uint256 dInS; // price of dest token denominated in src token uint256 sInD; // price of src token denominated in dest token if (_buy) { if (_useKyber) { ( dInS, sInD, _actualDestAmount, _actualSrcAmount ) = __kyberTrade( usdc, totalFundsInUSDC.mul(investment.stake).div( cToken.totalSupply() ), ERC20Detailed(token) ); } else { // 1inch trading ( dInS, sInD, _actualDestAmount, _actualSrcAmount ) = __oneInchTrade( usdc, totalFundsInUSDC.mul(investment.stake).div( cToken.totalSupply() ), ERC20Detailed(token), _calldata ); } require(_minPrice <= dInS && dInS <= _maxPrice); investment.buyPrice = dInS; investment.tokenAmount = _actualDestAmount; investment.buyCostInUSDC = _actualSrcAmount; } else { if (_useKyber) { ( dInS, sInD, _actualDestAmount, _actualSrcAmount ) = __kyberTrade( ERC20Detailed(token), investment.tokenAmount, usdc ); } else { ( dInS, sInD, _actualDestAmount, _actualSrcAmount ) = __oneInchTrade( ERC20Detailed(token), investment.tokenAmount, usdc, _calldata ); } require(_minPrice <= sInD && sInD <= _maxPrice); investment.sellPrice = sInD; } } /** * @notice Separated from createCompoundOrder() to avoid stack too deep error */ function __createCompoundOrder( bool _orderType, // True for shorting, false for longing address _tokenAddress, uint256 _stake, uint256 _collateralAmountInUSDC ) internal returns (CompoundOrder) { CompoundOrderFactory factory = CompoundOrderFactory( compoundFactoryAddr ); uint256 loanAmountInUSDC = _collateralAmountInUSDC .mul(COLLATERAL_RATIO_MODIFIER) .div(PRECISION) .mul(factory.getMarketCollateralFactor(_tokenAddress)) .div(PRECISION); CompoundOrder order = factory.createOrder( _tokenAddress, cycleNumber, _stake, _collateralAmountInUSDC, loanAmountInUSDC, _orderType ); return order; } /** * @notice Returns stake to manager after investment is sold, including reward/penalty based on performance */ function __returnStake(uint256 _receiveRepTokenAmount, uint256 _stake) internal { require(cToken.destroyTokens(address(this), _stake)); require(cToken.generateTokens(msg.sender, _receiveRepTokenAmount)); } /** * @notice Records risk taken in a trade based on stake and time of investment */ function __recordRisk( address _sender, uint256 _stake, uint256 _buyTime ) internal { _riskTakenInCycle[_sender][cycleNumber] = riskTakenInCycle( _sender, cycleNumber ) .add(_stake.mul(now.sub(_buyTime))); } }
pragma solidity ^0.5.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * NOTE: This call _does not revert_ if the signature is invalid, or * if the signer is otherwise unable to be retrieved. In those scenarios, * the zero address is returned. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { return (address(0)); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return address(0); } if (v != 27 && v != 28) { return address(0); } // If the signature is valid (and not malleable), return the signer address return ecrecover(hash, v, r, s); } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } }
pragma solidity 0.5.17; import "./PeakDeFiStorage.sol"; import "./derivatives/CompoundOrderFactory.sol"; import "@nomiclabs/buidler/console.sol"; /** * @title Part of the functions for PeakDeFiFund * @author Zefram Lou (Zebang Liu) */ contract PeakDeFiLogic2 is PeakDeFiStorage, Utils(address(0), address(0), address(0)) { /** * @notice Passes if the fund has not finalized the next smart contract to upgrade to */ modifier notReadyForUpgrade { require(hasFinalizedNextVersion == false); _; } /** * @notice Executes function only during the given cycle phase. * @param phase the cycle phase during which the function may be called */ modifier during(CyclePhase phase) { require(cyclePhase == phase); if (cyclePhase == CyclePhase.Intermission) { require(isInitialized); } _; } /** * Deposit & Withdraw */ function depositEther(address _referrer) public payable { bytes memory nil; depositEtherAdvanced(true, nil, _referrer); } /** * @notice Deposit Ether into the fund. Ether will be converted into USDC. * @param _useKyber true for Kyber Network, false for 1inch * @param _calldata calldata for 1inch trading * @param _referrer the referrer's address */ function depositEtherAdvanced( bool _useKyber, bytes memory _calldata, address _referrer ) public payable nonReentrant notReadyForUpgrade { // Buy USDC with ETH uint256 actualUSDCDeposited; uint256 actualETHDeposited; if (_useKyber) { (, , actualUSDCDeposited, actualETHDeposited) = __kyberTrade( ETH_TOKEN_ADDRESS, msg.value, usdc ); } else { (, , actualUSDCDeposited, actualETHDeposited) = __oneInchTrade( ETH_TOKEN_ADDRESS, msg.value, usdc, _calldata ); } // Send back leftover ETH uint256 leftOverETH = msg.value.sub(actualETHDeposited); if (leftOverETH > 0) { msg.sender.transfer(leftOverETH); } // Register investment __deposit(actualUSDCDeposited, _referrer); // Emit event emit Deposit( cycleNumber, msg.sender, address(ETH_TOKEN_ADDRESS), actualETHDeposited, actualUSDCDeposited, now ); } /** * @notice Deposit USDC Stablecoin into the fund. * @param _usdcAmount The amount of USDC to be deposited. May be different from actual deposited amount. * @param _referrer the referrer's address */ function depositUSDC(uint256 _usdcAmount, address _referrer) public nonReentrant notReadyForUpgrade { usdc.safeTransferFrom(msg.sender, address(this), _usdcAmount); // Register investment __deposit(_usdcAmount, _referrer); // Emit event emit Deposit( cycleNumber, msg.sender, USDC_ADDR, _usdcAmount, _usdcAmount, now ); } function depositToken( address _tokenAddr, uint256 _tokenAmount, address _referrer ) public { bytes memory nil; depositTokenAdvanced(_tokenAddr, _tokenAmount, true, nil, _referrer); } /** * @notice Deposit ERC20 tokens into the fund. Tokens will be converted into USDC. * @param _tokenAddr the address of the token to be deposited * @param _tokenAmount The amount of tokens to be deposited. May be different from actual deposited amount. * @param _useKyber true for Kyber Network, false for 1inch * @param _calldata calldata for 1inch trading * @param _referrer the referrer's address */ function depositTokenAdvanced( address _tokenAddr, uint256 _tokenAmount, bool _useKyber, bytes memory _calldata, address _referrer ) public nonReentrant notReadyForUpgrade isValidToken(_tokenAddr) { require( _tokenAddr != USDC_ADDR && _tokenAddr != address(ETH_TOKEN_ADDRESS) ); ERC20Detailed token = ERC20Detailed(_tokenAddr); token.safeTransferFrom(msg.sender, address(this), _tokenAmount); // Convert token into USDC uint256 actualUSDCDeposited; uint256 actualTokenDeposited; if (_useKyber) { (, , actualUSDCDeposited, actualTokenDeposited) = __kyberTrade( token, _tokenAmount, usdc ); } else { (, , actualUSDCDeposited, actualTokenDeposited) = __oneInchTrade( token, _tokenAmount, usdc, _calldata ); } // Give back leftover tokens uint256 leftOverTokens = _tokenAmount.sub(actualTokenDeposited); if (leftOverTokens > 0) { token.safeTransfer(msg.sender, leftOverTokens); } // Register investment __deposit(actualUSDCDeposited, _referrer); // Emit event emit Deposit( cycleNumber, msg.sender, _tokenAddr, actualTokenDeposited, actualUSDCDeposited, now ); } function withdrawEther(uint256 _amountInUSDC) external { bytes memory nil; withdrawEtherAdvanced(_amountInUSDC, true, nil); } /** * @notice Withdraws Ether by burning Shares. * @param _amountInUSDC Amount of funds to be withdrawn expressed in USDC. Fixed-point decimal. May be different from actual amount. * @param _useKyber true for Kyber Network, false for 1inch * @param _calldata calldata for 1inch trading */ function withdrawEtherAdvanced( uint256 _amountInUSDC, bool _useKyber, bytes memory _calldata ) public nonReentrant during(CyclePhase.Intermission) { // Buy ETH uint256 actualETHWithdrawn; uint256 actualUSDCWithdrawn; if (_useKyber) { (, , actualETHWithdrawn, actualUSDCWithdrawn) = __kyberTrade( usdc, _amountInUSDC, ETH_TOKEN_ADDRESS ); } else { (, , actualETHWithdrawn, actualUSDCWithdrawn) = __oneInchTrade( usdc, _amountInUSDC, ETH_TOKEN_ADDRESS, _calldata ); } __withdraw(actualUSDCWithdrawn); // Transfer Ether to user msg.sender.transfer(actualETHWithdrawn); // Emit event emit Withdraw( cycleNumber, msg.sender, address(ETH_TOKEN_ADDRESS), actualETHWithdrawn, actualUSDCWithdrawn, now ); } /** * @notice Withdraws Ether by burning Shares. * @param _amountInUSDC Amount of funds to be withdrawn expressed in USDC. Fixed-point decimal. May be different from actual amount. */ function withdrawUSDC(uint256 _amountInUSDC) external nonReentrant during(CyclePhase.Intermission) { __withdraw(_amountInUSDC); // Transfer USDC to user usdc.safeTransfer(msg.sender, _amountInUSDC); // Emit event emit Withdraw( cycleNumber, msg.sender, USDC_ADDR, _amountInUSDC, _amountInUSDC, now ); } function withdrawToken(address _tokenAddr, uint256 _amountInUSDC) external { bytes memory nil; withdrawTokenAdvanced(_tokenAddr, _amountInUSDC, true, nil); } /** * @notice Withdraws funds by burning Shares, and converts the funds into the specified token using Kyber Network. * @param _tokenAddr the address of the token to be withdrawn into the caller's account * @param _amountInUSDC The amount of funds to be withdrawn expressed in USDC. Fixed-point decimal. May be different from actual amount. * @param _useKyber true for Kyber Network, false for 1inch * @param _calldata calldata for 1inch trading */ function withdrawTokenAdvanced( address _tokenAddr, uint256 _amountInUSDC, bool _useKyber, bytes memory _calldata ) public during(CyclePhase.Intermission) nonReentrant isValidToken(_tokenAddr) { require( _tokenAddr != USDC_ADDR && _tokenAddr != address(ETH_TOKEN_ADDRESS) ); ERC20Detailed token = ERC20Detailed(_tokenAddr); // Convert USDC into desired tokens uint256 actualTokenWithdrawn; uint256 actualUSDCWithdrawn; if (_useKyber) { (, , actualTokenWithdrawn, actualUSDCWithdrawn) = __kyberTrade( usdc, _amountInUSDC, token ); } else { (, , actualTokenWithdrawn, actualUSDCWithdrawn) = __oneInchTrade( usdc, _amountInUSDC, token, _calldata ); } __withdraw(actualUSDCWithdrawn); // Transfer tokens to user token.safeTransfer(msg.sender, actualTokenWithdrawn); // Emit event emit Withdraw( cycleNumber, msg.sender, _tokenAddr, actualTokenWithdrawn, actualUSDCWithdrawn, now ); } /** * Manager registration */ /** * @notice Registers `msg.sender` as a manager, using USDC as payment. The more one pays, the more RepToken one gets. * There's a max RepToken amount that can be bought, and excess payment will be sent back to sender. */ function registerWithUSDC() public during(CyclePhase.Intermission) nonReentrant { require(!isPermissioned); require(managersOnboardedThisCycle < maxNewManagersPerCycle); managersOnboardedThisCycle = managersOnboardedThisCycle.add(1); uint256 peakStake = peakStaking.userStakeAmount(msg.sender); require(peakStake >= peakManagerStakeRequired); uint256 donationInUSDC = newManagerRepToken.mul(reptokenPrice).div(PRECISION); usdc.safeTransferFrom(msg.sender, address(this), donationInUSDC); __register(donationInUSDC); } /** * @notice Registers `msg.sender` as a manager, using ETH as payment. The more one pays, the more RepToken one gets. * There's a max RepToken amount that can be bought, and excess payment will be sent back to sender. */ function registerWithETH() public payable during(CyclePhase.Intermission) nonReentrant { require(!isPermissioned); require(managersOnboardedThisCycle < maxNewManagersPerCycle); managersOnboardedThisCycle = managersOnboardedThisCycle.add(1); uint256 peakStake = peakStaking.userStakeAmount(msg.sender); require(peakStake >= peakManagerStakeRequired); uint256 receivedUSDC; // trade ETH for USDC (, , receivedUSDC, ) = __kyberTrade(ETH_TOKEN_ADDRESS, msg.value, usdc); // if USDC value is greater than the amount required, return excess USDC to msg.sender uint256 donationInUSDC = newManagerRepToken.mul(reptokenPrice).div(PRECISION); if (receivedUSDC > donationInUSDC) { usdc.safeTransfer(msg.sender, receivedUSDC.sub(donationInUSDC)); receivedUSDC = donationInUSDC; } // register new manager __register(receivedUSDC); } /** * @notice Registers `msg.sender` as a manager, using tokens as payment. The more one pays, the more RepToken one gets. * There's a max RepToken amount that can be bought, and excess payment will be sent back to sender. * @param _token the token to be used for payment * @param _donationInTokens the amount of tokens to be used for registration, should use the token's native decimals */ function registerWithToken(address _token, uint256 _donationInTokens) public during(CyclePhase.Intermission) nonReentrant { require(!isPermissioned); require(managersOnboardedThisCycle < maxNewManagersPerCycle); managersOnboardedThisCycle = managersOnboardedThisCycle.add(1); uint256 peakStake = peakStaking.userStakeAmount(msg.sender); require(peakStake >= peakManagerStakeRequired); require( _token != address(0) && _token != address(ETH_TOKEN_ADDRESS) && _token != USDC_ADDR ); ERC20Detailed token = ERC20Detailed(_token); require(token.totalSupply() > 0); token.safeTransferFrom(msg.sender, address(this), _donationInTokens); uint256 receivedUSDC; (, , receivedUSDC, ) = __kyberTrade(token, _donationInTokens, usdc); // if USDC value is greater than the amount required, return excess USDC to msg.sender uint256 donationInUSDC = newManagerRepToken.mul(reptokenPrice).div(PRECISION); if (receivedUSDC > donationInUSDC) { usdc.safeTransfer(msg.sender, receivedUSDC.sub(donationInUSDC)); receivedUSDC = donationInUSDC; } // register new manager __register(receivedUSDC); } function peakAdminRegisterManager(address _manager, uint256 _reptokenAmount) public during(CyclePhase.Intermission) nonReentrant onlyOwner { require(isPermissioned); // mint REP for msg.sender require(cToken.generateTokens(_manager, _reptokenAmount)); // Set risk fallback base stake _baseRiskStakeFallback[_manager] = _baseRiskStakeFallback[_manager].add( _reptokenAmount ); // Set last active cycle for msg.sender to be the current cycle _lastActiveCycle[_manager] = cycleNumber; // emit events emit Register(_manager, 0, _reptokenAmount); } /** * @notice Sells tokens left over due to manager not selling or KyberNetwork not having enough volume. Callable by anyone. Money goes to developer. * @param _tokenAddr address of the token to be sold * @param _calldata the 1inch trade call data */ function sellLeftoverToken(address _tokenAddr, bytes calldata _calldata) external during(CyclePhase.Intermission) nonReentrant isValidToken(_tokenAddr) { ERC20Detailed token = ERC20Detailed(_tokenAddr); (, , uint256 actualUSDCReceived, ) = __oneInchTrade( token, getBalance(token, address(this)), usdc, _calldata ); totalFundsInUSDC = totalFundsInUSDC.add(actualUSDCReceived); } /** * @notice Sells CompoundOrder left over due to manager not selling or KyberNetwork not having enough volume. Callable by anyone. Money goes to developer. * @param _orderAddress address of the CompoundOrder to be sold */ function sellLeftoverCompoundOrder(address payable _orderAddress) public during(CyclePhase.Intermission) nonReentrant { // Load order info require(_orderAddress != address(0)); CompoundOrder order = CompoundOrder(_orderAddress); require(order.isSold() == false && order.cycleNumber() < cycleNumber); // Sell short order // Not using outputAmount returned by order.sellOrder() because _orderAddress could point to a malicious contract uint256 beforeUSDCBalance = usdc.balanceOf(address(this)); order.sellOrder(0, MAX_QTY); uint256 actualUSDCReceived = usdc.balanceOf(address(this)).sub( beforeUSDCBalance ); totalFundsInUSDC = totalFundsInUSDC.add(actualUSDCReceived); } /** * @notice Registers `msg.sender` as a manager. * @param _donationInUSDC the amount of USDC to be used for registration */ function __register(uint256 _donationInUSDC) internal { require( cToken.balanceOf(msg.sender) == 0 && userInvestments[msg.sender].length == 0 && userCompoundOrders[msg.sender].length == 0 ); // each address can only join once // mint REP for msg.sender uint256 repAmount = _donationInUSDC.mul(PRECISION).div(reptokenPrice); require(cToken.generateTokens(msg.sender, repAmount)); // Set risk fallback base stake _baseRiskStakeFallback[msg.sender] = repAmount; // Set last active cycle for msg.sender to be the current cycle _lastActiveCycle[msg.sender] = cycleNumber; // keep USDC in the fund totalFundsInUSDC = totalFundsInUSDC.add(_donationInUSDC); // emit events emit Register(msg.sender, _donationInUSDC, repAmount); } /** * @notice Handles deposits by minting PeakDeFi Shares & updating total funds. * @param _depositUSDCAmount The amount of the deposit in USDC * @param _referrer The deposit referrer */ function __deposit(uint256 _depositUSDCAmount, address _referrer) internal { // Register investment and give shares uint256 shareAmount; if (sToken.totalSupply() == 0 || totalFundsInUSDC == 0) { uint256 usdcDecimals = getDecimals(usdc); shareAmount = _depositUSDCAmount.mul(PRECISION).div(10**usdcDecimals); } else { shareAmount = _depositUSDCAmount.mul(sToken.totalSupply()).div( totalFundsInUSDC ); } require(sToken.generateTokens(msg.sender, shareAmount)); totalFundsInUSDC = totalFundsInUSDC.add(_depositUSDCAmount); totalFundsAtManagePhaseStart = totalFundsAtManagePhaseStart.add( _depositUSDCAmount ); // Handle peakReferralToken if (peakReward.canRefer(msg.sender, _referrer)) { peakReward.refer(msg.sender, _referrer); } address actualReferrer = peakReward.referrerOf(msg.sender); if (actualReferrer != address(0)) { require( peakReferralToken.generateTokens(actualReferrer, shareAmount) ); } } /** * @notice Handles deposits by burning PeakDeFi Shares & updating total funds. * @param _withdrawUSDCAmount The amount of the withdrawal in USDC */ function __withdraw(uint256 _withdrawUSDCAmount) internal { // Burn Shares uint256 shareAmount = _withdrawUSDCAmount.mul(sToken.totalSupply()).div( totalFundsInUSDC ); require(sToken.destroyTokens(msg.sender, shareAmount)); totalFundsInUSDC = totalFundsInUSDC.sub(_withdrawUSDCAmount); // Handle peakReferralToken address actualReferrer = peakReward.referrerOf(msg.sender); if (actualReferrer != address(0)) { uint256 balance = peakReferralToken.balanceOf(actualReferrer); uint256 burnReferralTokenAmount = shareAmount > balance ? balance : shareAmount; require( peakReferralToken.destroyTokens( actualReferrer, burnReferralTokenAmount ) ); } } }
// SPDX-License-Identifier: MIT pragma solidity >= 0.4.22 <0.8.0; library console { address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); function _sendLogPayload(bytes memory payload) private view { uint256 payloadLength = payload.length; address consoleAddress = CONSOLE_ADDRESS; assembly { let payloadStart := add(payload, 32) let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) } } function log() internal view { _sendLogPayload(abi.encodeWithSignature("log()")); } function logInt(int p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); } function logUint(uint p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); } function logString(string memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function logBool(bool p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function logAddress(address p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function logBytes(bytes memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); } function logByte(byte p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(byte)", p0)); } function logBytes1(bytes1 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); } function logBytes2(bytes2 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); } function logBytes3(bytes3 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); } function logBytes4(bytes4 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); } function logBytes5(bytes5 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); } function logBytes6(bytes6 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); } function logBytes7(bytes7 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); } function logBytes8(bytes8 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); } function logBytes9(bytes9 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); } function logBytes10(bytes10 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); } function logBytes11(bytes11 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); } function logBytes12(bytes12 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); } function logBytes13(bytes13 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); } function logBytes14(bytes14 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); } function logBytes15(bytes15 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); } function logBytes16(bytes16 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); } function logBytes17(bytes17 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); } function logBytes18(bytes18 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); } function logBytes19(bytes19 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); } function logBytes20(bytes20 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); } function logBytes21(bytes21 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); } function logBytes22(bytes22 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); } function logBytes23(bytes23 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); } function logBytes24(bytes24 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); } function logBytes25(bytes25 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); } function logBytes26(bytes26 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); } function logBytes27(bytes27 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); } function logBytes28(bytes28 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); } function logBytes29(bytes29 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); } function logBytes30(bytes30 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); } function logBytes31(bytes31 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); } function logBytes32(bytes32 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); } function log(uint p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); } function log(string memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function log(bool p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function log(address p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function log(uint p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); } function log(uint p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); } function log(uint p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); } function log(uint p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); } function log(string memory p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); } function log(string memory p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); } function log(string memory p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); } function log(string memory p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); } function log(bool p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); } function log(bool p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); } function log(bool p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); } function log(bool p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); } function log(address p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); } function log(address p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); } function log(address p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); } function log(address p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); } function log(uint p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); } function log(uint p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); } function log(uint p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); } function log(uint p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); } function log(uint p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); } function log(uint p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); } function log(uint p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); } function log(uint p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); } function log(uint p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); } function log(uint p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); } function log(uint p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); } function log(uint p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); } function log(uint p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); } function log(uint p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); } function log(uint p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); } function log(uint p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); } function log(string memory p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); } function log(string memory p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); } function log(string memory p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); } function log(string memory p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); } function log(string memory p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); } function log(string memory p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); } function log(string memory p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); } function log(string memory p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); } function log(string memory p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); } function log(string memory p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); } function log(string memory p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); } function log(string memory p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); } function log(string memory p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); } function log(string memory p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); } function log(string memory p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); } function log(string memory p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); } function log(bool p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); } function log(bool p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); } function log(bool p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); } function log(bool p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); } function log(bool p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); } function log(bool p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); } function log(bool p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); } function log(bool p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); } function log(bool p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); } function log(bool p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); } function log(bool p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); } function log(bool p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); } function log(bool p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); } function log(bool p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); } function log(bool p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); } function log(bool p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); } function log(address p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); } function log(address p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); } function log(address p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); } function log(address p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); } function log(address p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); } function log(address p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); } function log(address p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); } function log(address p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); } function log(address p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); } function log(address p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); } function log(address p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); } function log(address p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); } function log(address p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); } function log(address p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); } function log(address p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); } function log(address p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); } function log(uint p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); } }
pragma solidity 0.5.17; import "./PeakDeFiStorage.sol"; contract PeakDeFiLogic3 is PeakDeFiStorage, Utils(address(0), address(0), address(0)) { /** * @notice Passes if the fund has not finalized the next smart contract to upgrade to */ modifier notReadyForUpgrade { require(hasFinalizedNextVersion == false); _; } /** * @notice Executes function only during the given cycle phase. * @param phase the cycle phase during which the function may be called */ modifier during(CyclePhase phase) { require(cyclePhase == phase); if (cyclePhase == CyclePhase.Intermission) { require(isInitialized); } _; } /** * Next phase transition handler * @notice Moves the fund to the next phase in the investment cycle. */ function nextPhase() public nonReentrant { require( now >= startTimeOfCyclePhase.add(phaseLengths[uint256(cyclePhase)]) ); if (isInitialized == false) { // first cycle of this smart contract deployment // check whether ready for starting cycle isInitialized = true; require(proxyAddr != address(0)); // has initialized proxy require(proxy.peakdefiFundAddress() == address(this)); // upgrade complete require(hasInitializedTokenListings); // has initialized token listings // execute initialization function __init(); require( previousVersion == address(0) || (previousVersion != address(0) && getBalance(usdc, address(this)) > 0) ); // has transfered assets from previous version } else { // normal phase changing if (cyclePhase == CyclePhase.Intermission) { require(hasFinalizedNextVersion == false); // Shouldn't progress to next phase if upgrading // Update total funds at management phase's beginning totalFundsAtManagePhaseStart = totalFundsInUSDC; // reset number of managers onboarded managersOnboardedThisCycle = 0; } else if (cyclePhase == CyclePhase.Manage) { // Burn any RepToken left in PeakDeFiFund's account require( cToken.destroyTokens( address(this), cToken.balanceOf(address(this)) ) ); // Pay out commissions and fees uint256 profit = 0; uint256 usdcBalanceAtManagePhaseStart = totalFundsAtManagePhaseStart.add(totalCommissionLeft); if ( getBalance(usdc, address(this)) > usdcBalanceAtManagePhaseStart ) { profit = getBalance(usdc, address(this)).sub( usdcBalanceAtManagePhaseStart ); } totalFundsInUSDC = getBalance(usdc, address(this)) .sub(totalCommissionLeft) .sub(peakReferralTotalCommissionLeft); // Calculate manager commissions uint256 commissionThisCycle = COMMISSION_RATE .mul(profit) .add(ASSET_FEE_RATE.mul(totalFundsInUSDC)) .div(PRECISION); _totalCommissionOfCycle[cycleNumber] = totalCommissionOfCycle( cycleNumber ) .add(commissionThisCycle); // account for penalties totalCommissionLeft = totalCommissionLeft.add( commissionThisCycle ); // Calculate referrer commissions uint256 peakReferralCommissionThisCycle = PEAK_COMMISSION_RATE .mul(profit) .mul(peakReferralToken.totalSupply()) .div(sToken.totalSupply()) .div(PRECISION); _peakReferralTotalCommissionOfCycle[cycleNumber] = peakReferralTotalCommissionOfCycle( cycleNumber ) .add(peakReferralCommissionThisCycle); peakReferralTotalCommissionLeft = peakReferralTotalCommissionLeft .add(peakReferralCommissionThisCycle); totalFundsInUSDC = getBalance(usdc, address(this)) .sub(totalCommissionLeft) .sub(peakReferralTotalCommissionLeft); // Give the developer PeakDeFi shares inflation funding uint256 devFunding = devFundingRate .mul(sToken.totalSupply()) .div(PRECISION); require(sToken.generateTokens(devFundingAccount, devFunding)); // Emit event emit TotalCommissionPaid( cycleNumber, totalCommissionOfCycle(cycleNumber) ); emit PeakReferralTotalCommissionPaid( cycleNumber, peakReferralTotalCommissionOfCycle(cycleNumber) ); _managePhaseEndBlock[cycleNumber] = block.number; // Clear/update upgrade related data if (nextVersion == address(this)) { // The developer proposed a candidate, but the managers decide to not upgrade at all // Reset upgrade process delete nextVersion; delete hasFinalizedNextVersion; } if (nextVersion != address(0)) { hasFinalizedNextVersion = true; emit FinalizedNextVersion(cycleNumber, nextVersion); } // Start new cycle cycleNumber = cycleNumber.add(1); } cyclePhase = CyclePhase(addmod(uint256(cyclePhase), 1, 2)); } startTimeOfCyclePhase = now; // Reward caller if they're a manager if (cToken.balanceOf(msg.sender) > 0) { require(cToken.generateTokens(msg.sender, NEXT_PHASE_REWARD)); } emit ChangedPhase( cycleNumber, uint256(cyclePhase), now, totalFundsInUSDC ); } /** * @notice Initializes several important variables after smart contract upgrade */ function __init() internal { _managePhaseEndBlock[cycleNumber.sub(1)] = block.number; // load values from previous version totalCommissionLeft = previousVersion == address(0) ? 0 : PeakDeFiStorage(previousVersion).totalCommissionLeft(); totalFundsInUSDC = getBalance(usdc, address(this)).sub( totalCommissionLeft ); } /** * Upgrading functions */ /** * @notice Allows the developer to propose a candidate smart contract for the fund to upgrade to. * The developer may change the candidate during the Intermission phase. * @param _candidate the address of the candidate smart contract * @return True if successfully changed candidate, false otherwise. */ function developerInitiateUpgrade(address payable _candidate) public onlyOwner notReadyForUpgrade during(CyclePhase.Intermission) nonReentrant returns (bool _success) { if (_candidate == address(0) || _candidate == address(this)) { return false; } nextVersion = _candidate; emit DeveloperInitiatedUpgrade(cycleNumber, _candidate); return true; } /** Commission functions */ /** * @notice Returns the commission balance of `_manager` * @return the commission balance and the received penalty, denoted in USDC */ function commissionBalanceOf(address _manager) public view returns (uint256 _commission, uint256 _penalty) { if (lastCommissionRedemption(_manager) >= cycleNumber) { return (0, 0); } uint256 cycle = lastCommissionRedemption(_manager) > 0 ? lastCommissionRedemption(_manager) : 1; uint256 cycleCommission; uint256 cyclePenalty; for (; cycle < cycleNumber; cycle++) { (cycleCommission, cyclePenalty) = commissionOfAt(_manager, cycle); _commission = _commission.add(cycleCommission); _penalty = _penalty.add(cyclePenalty); } } /** * @notice Returns the commission amount received by `_manager` in the `_cycle`th cycle * @return the commission amount and the received penalty, denoted in USDC */ function commissionOfAt(address _manager, uint256 _cycle) public view returns (uint256 _commission, uint256 _penalty) { if (hasRedeemedCommissionForCycle(_manager, _cycle)) { return (0, 0); } // take risk into account uint256 baseRepTokenBalance = cToken.balanceOfAt( _manager, managePhaseEndBlock(_cycle.sub(1)) ); uint256 baseStake = baseRepTokenBalance == 0 ? baseRiskStakeFallback(_manager) : baseRepTokenBalance; if (baseRepTokenBalance == 0 && baseRiskStakeFallback(_manager) == 0) { return (0, 0); } uint256 riskTakenProportion = riskTakenInCycle(_manager, _cycle) .mul(PRECISION) .div(baseStake.mul(MIN_RISK_TIME)); // risk / threshold riskTakenProportion = riskTakenProportion > PRECISION ? PRECISION : riskTakenProportion; // max proportion is 1 uint256 fullCommission = totalCommissionOfCycle(_cycle) .mul(cToken.balanceOfAt(_manager, managePhaseEndBlock(_cycle))) .div(cToken.totalSupplyAt(managePhaseEndBlock(_cycle))); _commission = fullCommission.mul(riskTakenProportion).div(PRECISION); _penalty = fullCommission.sub(_commission); } /** * @notice Redeems commission. */ function redeemCommission(bool _inShares) public during(CyclePhase.Intermission) nonReentrant { uint256 commission = __redeemCommission(); if (_inShares) { // Deposit commission into fund __deposit(commission); // Emit deposit event emit Deposit( cycleNumber, msg.sender, USDC_ADDR, commission, commission, now ); } else { // Transfer the commission in USDC usdc.safeTransfer(msg.sender, commission); } } /** * @notice Redeems commission for a particular cycle. * @param _inShares true to redeem in PeakDeFi Shares, false to redeem in USDC * @param _cycle the cycle for which the commission will be redeemed. * Commissions for a cycle will be redeemed during the Intermission phase of the next cycle, so _cycle must < cycleNumber. */ function redeemCommissionForCycle(bool _inShares, uint256 _cycle) public during(CyclePhase.Intermission) nonReentrant { require(_cycle < cycleNumber); uint256 commission = __redeemCommissionForCycle(_cycle); if (_inShares) { // Deposit commission into fund __deposit(commission); // Emit deposit event emit Deposit( cycleNumber, msg.sender, USDC_ADDR, commission, commission, now ); } else { // Transfer the commission in USDC usdc.safeTransfer(msg.sender, commission); } } /** * @notice Redeems the commission for all previous cycles. Updates the related variables. * @return the amount of commission to be redeemed */ function __redeemCommission() internal returns (uint256 _commission) { require(lastCommissionRedemption(msg.sender) < cycleNumber); uint256 penalty; // penalty received for not taking enough risk (_commission, penalty) = commissionBalanceOf(msg.sender); // record the redemption to prevent double-redemption for ( uint256 i = lastCommissionRedemption(msg.sender); i < cycleNumber; i++ ) { _hasRedeemedCommissionForCycle[msg.sender][i] = true; } _lastCommissionRedemption[msg.sender] = cycleNumber; // record the decrease in commission pool totalCommissionLeft = totalCommissionLeft.sub(_commission); // include commission penalty to this cycle's total commission pool _totalCommissionOfCycle[cycleNumber] = totalCommissionOfCycle( cycleNumber ) .add(penalty); // clear investment arrays to save space delete userInvestments[msg.sender]; delete userCompoundOrders[msg.sender]; emit CommissionPaid(cycleNumber, msg.sender, _commission); } /** * @notice Redeems commission for a particular cycle. Updates the related variables. * @param _cycle the cycle for which the commission will be redeemed * @return the amount of commission to be redeemed */ function __redeemCommissionForCycle(uint256 _cycle) internal returns (uint256 _commission) { require(!hasRedeemedCommissionForCycle(msg.sender, _cycle)); uint256 penalty; // penalty received for not taking enough risk (_commission, penalty) = commissionOfAt(msg.sender, _cycle); _hasRedeemedCommissionForCycle[msg.sender][_cycle] = true; // record the decrease in commission pool totalCommissionLeft = totalCommissionLeft.sub(_commission); // include commission penalty to this cycle's total commission pool _totalCommissionOfCycle[cycleNumber] = totalCommissionOfCycle( cycleNumber ) .add(penalty); // clear investment arrays to save space delete userInvestments[msg.sender]; delete userCompoundOrders[msg.sender]; emit CommissionPaid(_cycle, msg.sender, _commission); } /** * @notice Handles deposits by minting PeakDeFi Shares & updating total funds. * @param _depositUSDCAmount The amount of the deposit in USDC */ function __deposit(uint256 _depositUSDCAmount) internal { // Register investment and give shares if (sToken.totalSupply() == 0 || totalFundsInUSDC == 0) { require(sToken.generateTokens(msg.sender, _depositUSDCAmount)); } else { require( sToken.generateTokens( msg.sender, _depositUSDCAmount.mul(sToken.totalSupply()).div( totalFundsInUSDC ) ) ); } totalFundsInUSDC = totalFundsInUSDC.add(_depositUSDCAmount); } /** PeakDeFi */ /** * @notice Returns the commission balance of `_referrer` * @return the commission balance, denoted in USDC */ function peakReferralCommissionBalanceOf(address _referrer) public view returns (uint256 _commission) { if (peakReferralLastCommissionRedemption(_referrer) >= cycleNumber) { return (0); } uint256 cycle = peakReferralLastCommissionRedemption(_referrer) > 0 ? peakReferralLastCommissionRedemption(_referrer) : 1; uint256 cycleCommission; for (; cycle < cycleNumber; cycle++) { (cycleCommission) = peakReferralCommissionOfAt(_referrer, cycle); _commission = _commission.add(cycleCommission); } } /** * @notice Returns the commission amount received by `_referrer` in the `_cycle`th cycle * @return the commission amount, denoted in USDC */ function peakReferralCommissionOfAt(address _referrer, uint256 _cycle) public view returns (uint256 _commission) { _commission = peakReferralTotalCommissionOfCycle(_cycle) .mul( peakReferralToken.balanceOfAt( _referrer, managePhaseEndBlock(_cycle) ) ) .div(peakReferralToken.totalSupplyAt(managePhaseEndBlock(_cycle))); } /** * @notice Redeems commission. */ function peakReferralRedeemCommission() public during(CyclePhase.Intermission) nonReentrant { uint256 commission = __peakReferralRedeemCommission(); // Transfer the commission in USDC usdc.safeApprove(address(peakReward), commission); peakReward.payCommission(msg.sender, address(usdc), commission, false); } /** * @notice Redeems commission for a particular cycle. * @param _cycle the cycle for which the commission will be redeemed. * Commissions for a cycle will be redeemed during the Intermission phase of the next cycle, so _cycle must < cycleNumber. */ function peakReferralRedeemCommissionForCycle(uint256 _cycle) public during(CyclePhase.Intermission) nonReentrant { require(_cycle < cycleNumber); uint256 commission = __peakReferralRedeemCommissionForCycle(_cycle); // Transfer the commission in USDC usdc.safeApprove(address(peakReward), commission); peakReward.payCommission(msg.sender, address(usdc), commission, false); } /** * @notice Redeems the commission for all previous cycles. Updates the related variables. * @return the amount of commission to be redeemed */ function __peakReferralRedeemCommission() internal returns (uint256 _commission) { require(peakReferralLastCommissionRedemption(msg.sender) < cycleNumber); _commission = peakReferralCommissionBalanceOf(msg.sender); // record the redemption to prevent double-redemption for ( uint256 i = peakReferralLastCommissionRedemption(msg.sender); i < cycleNumber; i++ ) { _peakReferralHasRedeemedCommissionForCycle[msg.sender][i] = true; } _peakReferralLastCommissionRedemption[msg.sender] = cycleNumber; // record the decrease in commission pool peakReferralTotalCommissionLeft = peakReferralTotalCommissionLeft.sub( _commission ); emit PeakReferralCommissionPaid(cycleNumber, msg.sender, _commission); } /** * @notice Redeems commission for a particular cycle. Updates the related variables. * @param _cycle the cycle for which the commission will be redeemed * @return the amount of commission to be redeemed */ function __peakReferralRedeemCommissionForCycle(uint256 _cycle) internal returns (uint256 _commission) { require(!peakReferralHasRedeemedCommissionForCycle(msg.sender, _cycle)); _commission = peakReferralCommissionOfAt(msg.sender, _cycle); _peakReferralHasRedeemedCommissionForCycle[msg.sender][_cycle] = true; // record the decrease in commission pool peakReferralTotalCommissionLeft = peakReferralTotalCommissionLeft.sub( _commission ); emit PeakReferralCommissionPaid(_cycle, msg.sender, _commission); } }
pragma solidity 0.5.17; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; import "../interfaces/CERC20.sol"; import "../interfaces/Comptroller.sol"; contract TestCERC20 is CERC20 { using SafeMath for uint; uint public constant PRECISION = 10 ** 18; uint public constant MAX_UINT = 2 ** 256 - 1; address public _underlying; uint public _exchangeRateCurrent = 10 ** (18 - 8) * PRECISION; mapping(address => uint) public _balanceOf; mapping(address => uint) public _borrowBalanceCurrent; Comptroller public COMPTROLLER; constructor(address __underlying, address _comptrollerAddr) public { _underlying = __underlying; COMPTROLLER = Comptroller(_comptrollerAddr); } function mint(uint mintAmount) external returns (uint) { ERC20Detailed token = ERC20Detailed(_underlying); require(token.transferFrom(msg.sender, address(this), mintAmount)); _balanceOf[msg.sender] = _balanceOf[msg.sender].add(mintAmount.mul(10 ** this.decimals()).div(PRECISION)); return 0; } function redeemUnderlying(uint redeemAmount) external returns (uint) { _balanceOf[msg.sender] = _balanceOf[msg.sender].sub(redeemAmount.mul(10 ** this.decimals()).div(PRECISION)); ERC20Detailed token = ERC20Detailed(_underlying); require(token.transfer(msg.sender, redeemAmount)); return 0; } function borrow(uint amount) external returns (uint) { // add to borrow balance _borrowBalanceCurrent[msg.sender] = _borrowBalanceCurrent[msg.sender].add(amount); // transfer asset ERC20Detailed token = ERC20Detailed(_underlying); require(token.transfer(msg.sender, amount)); return 0; } function repayBorrow(uint amount) external returns (uint) { // accept repayment ERC20Detailed token = ERC20Detailed(_underlying); uint256 repayAmount = amount == MAX_UINT ? _borrowBalanceCurrent[msg.sender] : amount; require(token.transferFrom(msg.sender, address(this), repayAmount)); // subtract from borrow balance _borrowBalanceCurrent[msg.sender] = _borrowBalanceCurrent[msg.sender].sub(repayAmount); return 0; } function balanceOf(address account) external view returns (uint) { return _balanceOf[account]; } function borrowBalanceCurrent(address account) external returns (uint) { return _borrowBalanceCurrent[account]; } function underlying() external view returns (address) { return _underlying; } function exchangeRateCurrent() external returns (uint) { return _exchangeRateCurrent; } function decimals() external view returns (uint) { return 8; } }
pragma solidity 0.5.17; import "./TestCERC20.sol"; contract TestCERC20Factory { mapping(address => address) public createdTokens; event CreatedToken(address underlying, address cToken); function newToken(address underlying, address comptroller) public returns(address) { require(createdTokens[underlying] == address(0)); TestCERC20 token = new TestCERC20(underlying, comptroller); createdTokens[underlying] = address(token); emit CreatedToken(underlying, address(token)); return address(token); } }
pragma solidity 0.5.17; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../interfaces/CEther.sol"; import "../interfaces/Comptroller.sol"; contract TestCEther is CEther { using SafeMath for uint; uint public constant PRECISION = 10 ** 18; uint public _exchangeRateCurrent = 10 ** (18 - 8) * PRECISION; mapping(address => uint) public _balanceOf; mapping(address => uint) public _borrowBalanceCurrent; Comptroller public COMPTROLLER; constructor(address _comptrollerAddr) public { COMPTROLLER = Comptroller(_comptrollerAddr); } function mint() external payable { _balanceOf[msg.sender] = _balanceOf[msg.sender].add(msg.value.mul(10 ** this.decimals()).div(PRECISION)); } function redeemUnderlying(uint redeemAmount) external returns (uint) { _balanceOf[msg.sender] = _balanceOf[msg.sender].sub(redeemAmount.mul(10 ** this.decimals()).div(PRECISION)); msg.sender.transfer(redeemAmount); return 0; } function borrow(uint amount) external returns (uint) { // add to borrow balance _borrowBalanceCurrent[msg.sender] = _borrowBalanceCurrent[msg.sender].add(amount); // transfer asset msg.sender.transfer(amount); return 0; } function repayBorrow() external payable { _borrowBalanceCurrent[msg.sender] = _borrowBalanceCurrent[msg.sender].sub(msg.value); } function balanceOf(address account) external view returns (uint) { return _balanceOf[account]; } function borrowBalanceCurrent(address account) external returns (uint) { return _borrowBalanceCurrent[account]; } function exchangeRateCurrent() external returns (uint) { return _exchangeRateCurrent; } function decimals() external view returns (uint) { return 8; } function() external payable {} }
pragma solidity 0.5.17; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../interfaces/Comptroller.sol"; import "../interfaces/PriceOracle.sol"; import "../interfaces/CERC20.sol"; contract TestComptroller is Comptroller { using SafeMath for uint; uint256 internal constant PRECISION = 10 ** 18; mapping(address => address[]) public getAssetsIn; uint256 internal collateralFactor = 2 * PRECISION / 3; constructor() public {} function enterMarkets(address[] calldata cTokens) external returns (uint[] memory) { uint[] memory errors = new uint[](cTokens.length); for (uint256 i = 0; i < cTokens.length; i = i.add(1)) { getAssetsIn[msg.sender].push(cTokens[i]); errors[i] = 0; } return errors; } function markets(address /*cToken*/) external view returns (bool isListed, uint256 collateralFactorMantissa) { return (true, collateralFactor); } }
pragma solidity 0.5.17; import "../interfaces/KyberNetwork.sol"; import "../Utils.sol"; import "@openzeppelin/contracts/ownership/Ownable.sol"; contract TestKyberNetwork is KyberNetwork, Utils(address(0), address(0), address(0)), Ownable { mapping(address => uint256) public priceInUSDC; constructor(address[] memory _tokens, uint256[] memory _pricesInUSDC) public { for (uint256 i = 0; i < _tokens.length; i = i.add(1)) { priceInUSDC[_tokens[i]] = _pricesInUSDC[i]; } } function setTokenPrice(address _token, uint256 _priceInUSDC) public onlyOwner { priceInUSDC[_token] = _priceInUSDC; } function setAllTokenPrices(address[] memory _tokens, uint256[] memory _pricesInUSDC) public onlyOwner { for (uint256 i = 0; i < _tokens.length; i = i.add(1)) { priceInUSDC[_tokens[i]] = _pricesInUSDC[i]; } } function getExpectedRate(ERC20Detailed src, ERC20Detailed dest, uint /*srcQty*/) external view returns (uint expectedRate, uint slippageRate) { uint256 result = priceInUSDC[address(src)].mul(10**getDecimals(dest)).mul(PRECISION).div(priceInUSDC[address(dest)].mul(10**getDecimals(src))); return (result, result); } function tradeWithHint( ERC20Detailed src, uint srcAmount, ERC20Detailed dest, address payable destAddress, uint maxDestAmount, uint /*minConversionRate*/, address /*walletId*/, bytes calldata /*hint*/ ) external payable returns(uint) { require(calcDestAmount(src, srcAmount, dest) <= maxDestAmount); if (address(src) == address(ETH_TOKEN_ADDRESS)) { require(srcAmount == msg.value); } else { require(src.transferFrom(msg.sender, address(this), srcAmount)); } if (address(dest) == address(ETH_TOKEN_ADDRESS)) { destAddress.transfer(calcDestAmount(src, srcAmount, dest)); } else { require(dest.transfer(destAddress, calcDestAmount(src, srcAmount, dest))); } return calcDestAmount(src, srcAmount, dest); } function calcDestAmount( ERC20Detailed src, uint srcAmount, ERC20Detailed dest ) internal view returns (uint destAmount) { return srcAmount.mul(priceInUSDC[address(src)]).mul(10**getDecimals(dest)).div(priceInUSDC[address(dest)].mul(10**getDecimals(src))); } function() external payable {} }
pragma solidity 0.5.17; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/ownership/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; import "../interfaces/PriceOracle.sol"; import "../interfaces/CERC20.sol"; contract TestPriceOracle is PriceOracle, Ownable { using SafeMath for uint; uint public constant PRECISION = 10 ** 18; address public CETH_ADDR; mapping(address => uint256) public priceInUSD; constructor(address[] memory _tokens, uint256[] memory _pricesInUSD, address _cETH) public { for (uint256 i = 0; i < _tokens.length; i = i.add(1)) { priceInUSD[_tokens[i]] = _pricesInUSD[i]; } CETH_ADDR = _cETH; } function setTokenPrice(address _token, uint256 _priceInUSD) public onlyOwner { priceInUSD[_token] = _priceInUSD; } function getUnderlyingPrice(address _cToken) external view returns (uint) { if (_cToken == CETH_ADDR) { return priceInUSD[_cToken]; } CERC20 cToken = CERC20(_cToken); ERC20Detailed underlying = ERC20Detailed(cToken.underlying()); return priceInUSD[_cToken].mul(PRECISION).div(10 ** uint256(underlying.decimals())); } }
pragma solidity 0.5.17; import "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol"; /** * @title An ERC20 token used for testing. * @author Zefram Lou (Zebang Liu) */ contract TestToken is ERC20Mintable, ERC20Burnable, ERC20Detailed { constructor(string memory name, string memory symbol, uint8 decimals) public ERC20Detailed(name, symbol, decimals) {} }
pragma solidity 0.5.17; import "./TestToken.sol"; contract TestTokenFactory { mapping(bytes32 => address) public createdTokens; event CreatedToken(string symbol, address addr); function newToken(string memory name, string memory symbol, uint8 decimals) public returns(address) { bytes32 symbolHash = keccak256(abi.encodePacked(symbol)); require(createdTokens[symbolHash] == address(0)); TestToken token = new TestToken(name, symbol, decimals); token.addMinter(msg.sender); token.renounceMinter(); createdTokens[symbolHash] = address(token); emit CreatedToken(symbol, address(token)); return address(token); } function getToken(string memory symbol) public view returns(address) { return createdTokens[keccak256(abi.encodePacked(symbol))]; } }
pragma solidity 0.5.17; contract TestUniswapOracle { function update() external returns (bool success) { return true; } function consult(address token, uint256 amountIn) external view returns (uint256 amountOut) { return 3 * 10**5; // 1 PEAK = 0.30 USDC } }
{ "metadata": { "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_marketPeakWallet","type":"address"},{"internalType":"address","name":"_peakStaking","type":"address"},{"internalType":"address","name":"_peakToken","type":"address"},{"internalType":"address","name":"_stablecoin","type":"address"},{"internalType":"address","name":"_oracle","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"changeAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"positive","type":"bool"}],"name":"ChangedCareerValue","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"referrer","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"level","type":"uint8"}],"name":"PayCommission","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldRank","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRank","type":"uint256"}],"name":"RankChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"peakReward","type":"uint256"}],"name":"ReceiveRankReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"referrer","type":"address"}],"name":"Register","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"SignerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"SignerRemoved","type":"event"},{"constant":true,"inputs":[],"name":"PEAK_MINT_CAP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addSigner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"canRankUp","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"referrer","type":"address"}],"name":"canRefer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"careerValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"commissionPercentages","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"commissionStakeRequirements","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"cvRankOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"downlineRanks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"incCVInPeak","type":"uint256"}],"name":"incrementCareerValueInPeak","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"incCV","type":"uint256"}],"name":"incrementCareerValueInUsdc","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isSigner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isUser","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"marketPeakWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mintedPeakTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"address[]","name":"referrers","type":"address[]"}],"name":"multiRefer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IUniswapOracle","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"referrer","type":"address"},{"internalType":"address","name":"commissionToken","type":"address"},{"internalType":"uint256","name":"rawCommission","type":"uint256"},{"internalType":"bool","name":"returnLeftovers","type":"bool"}],"name":"payCommission","outputs":[{"internalType":"uint256","name":"leftoverAmount","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"peakStaking","outputs":[{"internalType":"contract PeakStaking","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"peakToken","outputs":[{"internalType":"contract PeakToken","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rankOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"rankReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rankUp","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"referrer","type":"address"}],"name":"refer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"referrerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceSigner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"stablecoin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506040516200270038038062002700833981810160405260a08110156200003757600080fd5b508051602082015160408301516060840151608090940151929391929091906200007c6200006d6001600160e01b036200054c16565b6001600160e01b036200055016565b600780546001808201835567016345785d8a00007fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6889283015582548082018455668e1bc9bf040000908301558254808201845566470de4df8200009083015582548082018455662386f26fc1000090830181905583548083018555830181905583548083018555830155825480820184556611c37937e080009083018190558354808301909455929091019190915560088054918201815560008181527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3909201919091556200017f6305f5e1006107d0620005a2602090811b6200161217901c565b815460018101835560009283526020928390200155600890620001b5906305f5e10090610fa09062001612620005a2821b17901c565b815460018101835560009283526020928390200155600890620001eb906305f5e100906117709062001612620005a2821b17901c565b81546001810183556000928352602092839020015560089062000221906305f5e10090611b589062001612620005a2821b17901c565b81546001810183556000928352602092839020015560089062000257906305f5e10090611f409062001612620005a2821b17901c565b8154600181018355600092835260209283902001556008906200028d906305f5e100906123289062001612620005a2821b17901c565b815460018101835560009283526020928390200155600890620002c3906305f5e100906127109062001612620005a2821b17901c565b815460018101835560009283526020832001555b6008811015620004e857600080620002fd83600162000609602090811b6200174617901c565b90505b60088111620004c357806001141562000352576200034a620003356064620f4240620005a260201b620016121790919060201c565b836200060960201b620017461790919060201c565b915062000486565b80600214156200037f576200034a6200033561012c620f4240620005a260201b620016121790919060201c565b8060031415620003ac576200034a62000335610258620f4240620005a260201b620016121790919060201c565b8060041415620003d9576200034a620003356104b0620f4240620005a260201b620016121790919060201c565b806005141562000406576200034a62000335610960620f4240620005a260201b620016121790919060201c565b806006141562000433576200034a62000335611d4c620f4240620005a260201b620016121790919060201c565b806007141562000460576200034a62000335613a98620f4240620005a260201b620016121790919060201c565b620004836200033561c350620f4240620005a260201b620016121790919060201c565b91505b60008381526005602090815260408083208484528252909120839055620004bb9082906001906200174662000609821b17901c565b905062000300565b5050620004e06001826200060960201b620017461790919060201c565b9050620002d7565b50600a80546001600160a01b03199081166001600160a01b0397881617909155600b8054821695871695909517909455600c8054851693861693909317909255600d80548416918516919091179055600e805490921692169190911790556200075a565b3390565b6200056b8160006200066460201b62001cdb1790919060201c565b6040516001600160a01b038216907f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f2490600090a250565b600082620005b35750600062000603565b82820282848281620005c157fe5b0414620006005760405162461bcd60e51b8152600401808060200182810382526021815260200180620026bd6021913960400191505060405180910390fd5b90505b92915050565b60008282018381101562000600576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6200067982826001600160e01b03620006f116565b15620006cc576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b60006001600160a01b0382166200073a5760405162461bcd60e51b8152600401808060200182810382526022815260200180620026de6022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b611f53806200076a6000396000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c8063874c1daf116100f9578063e5c8b03d11610097578063f33a559111610071578063f33a55911461053a578063f454425514610557578063fb1f111c14610585578063fd7f65bd146105a8576101a9565b8063e5c8b03d14610504578063e9cbd8221461050c578063eb12d61e14610514576101a9565b8063c298a69f116100d3578063c298a69f146104a8578063c93f636a146104b0578063d21cacdf146104b8578063db203e6c146104de576101a9565b8063874c1daf146103945780638ef4121f146103ba57806397017cae1461047c576101a9565b8063650f5443116101665780637cf6f53a116101405780637cf6f53a1461030e5780637d49ac361461033a5780637dc0d1d0146103665780637df73e271461036e576101a9565b8063650f5443146102825780636796ec30146102c05780636f8bd036146102e6576101a9565b806309164fe6146101ae57806310f79eb5146101c8578063212c868f1461020a5780633131be901461022e5780634209fff1146102365780635497f9b71461025c575b600080fd5b6101b66105c5565b60408051918252519081900360200190f35b6101f6600480360360408110156101de57600080fd5b506001600160a01b03813581169160200135166105cb565b604080519115158252519081900360200190f35b610212610637565b604080516001600160a01b039092168252519081900360200190f35b610212610646565b6101f66004803603602081101561024c57600080fd5b50356001600160a01b0316610655565b6101b66004803603602081101561027257600080fd5b50356001600160a01b031661066a565b6101b66004803603608081101561029857600080fd5b506001600160a01b03813581169160208101359091169060408101359060600135151561067c565b6101b6600480360360208110156102d657600080fd5b50356001600160a01b0316610947565b61030c600480360360208110156102fc57600080fd5b50356001600160a01b0316610a9a565b005b6101b66004803603604081101561032457600080fd5b506001600160a01b038135169060200135610dc4565b61030c6004803603604081101561035057600080fd5b506001600160a01b038135169060200135610de1565b610212610f21565b6101f66004803603602081101561038457600080fd5b50356001600160a01b0316610f30565b6101b6600480360360208110156103aa57600080fd5b50356001600160a01b0316610f42565b61030c600480360360408110156103d057600080fd5b8101906020810181356401000000008111156103eb57600080fd5b8201836020820111156103fd57600080fd5b8035906020019184602083028401116401000000008311171561041f57600080fd5b91939092909160208101903564010000000081111561043d57600080fd5b82018360208201111561044f57600080fd5b8035906020019184602083028401116401000000008311171561047157600080fd5b509092509050610f54565b61030c6004803603604081101561049257600080fd5b506001600160a01b038135169060200135611032565b61021261119d565b6101b66111ac565b610212600480360360208110156104ce57600080fd5b50356001600160a01b03166111b7565b6101f6600480360360208110156104f457600080fd5b50356001600160a01b03166111d2565b61030c61123a565b61021261124c565b61030c6004803603602081101561052a57600080fd5b50356001600160a01b031661125b565b6101b66004803603602081101561055057600080fd5b50356112ad565b61030c6004803603604081101561056d57600080fd5b506001600160a01b03813581169160200135166112cb565b6101b66004803603604081101561059b57600080fd5b5080359060200135611500565b6101b6600480360360208110156105be57600080fd5b503561151d565b60095481565b6001600160a01b03821660009081526002602052604081205460ff161580156106065750816001600160a01b0316836001600160a01b031614155b801561061a57506001600160a01b03831615155b801561062e57506001600160a01b03821615155b90505b92915050565b600a546001600160a01b031681565b600b546001600160a01b031681565b60026020526000908152604090205460ff1681565b60036020526000908152604090205481565b6001600160a01b038416600090815260026020526040812054859060ff166106eb576001600160a01b0381166000818152600260209081526040808320805460ff191660011790558051938452908301919091528051600080516020611e268339815191529281900390910190a15b6106fb6106f661152a565b610f30565b6107365760405162461bcd60e51b8152600401808060200182810382526030815260200180611ec56030913960400191505060405180910390fd5b846107526001600160a01b03821633308863ffffffff61152f16565b868560005b6001600160a01b038316158015906107725750600860ff8216105b156108ea5760088160ff168154811061078757fe5b906000526020600020015461079b8461158f565b106108c35760006107e76702c68af0bb1400006107db60078560ff16815481106107c157fe5b90600052602060002001548c61161290919063ffffffff16565b9063ffffffff61166b16565b9050828111156107f45750815b61080e6001600160a01b038616858363ffffffff6116ad16565b61081e838263ffffffff61170416565b600c549093506001600160a01b038b811691161415610846576108418482611032565b610866565b600d546001600160a01b038b811691161415610866576108668482610de1565b604080516001600160a01b03808e16825280871660208301528c16818301526060810183905260ff8416608082015290517f83e0d93d1f31c32a251200957cfc5c8dae763ff279427f6cf07b5f1e77f488439181900360a00190a1505b6001600160a01b039283166000908152600160208190526040909120549093169201610757565b86156109155761090a6001600160a01b038516338463ffffffff6116ad16565b50935061093e915050565b600a54610935906001600160a01b0386811691168463ffffffff6116ad16565b60009550505050505b50949350505050565b6001600160a01b038116600090815260036020526040812054610974620f4240606463ffffffff61161216565b811015610985576000915050610a95565b610999620f424060fa63ffffffff61161216565b8110156109aa576001915050610a95565b6109bf620f42406102ee63ffffffff61161216565b8110156109d0576002915050610a95565b6109e5620f42406105dc63ffffffff61161216565b8110156109f6576003915050610a95565b610a0b620f4240610bb863ffffffff61161216565b811015610a1c576004915050610a95565b610a31620f424061271063ffffffff61161216565b811015610a42576005915050610a95565b610a57620f424061c35063ffffffff61161216565b811015610a68576006915050610a95565b610a7e620f4240620249f063ffffffff61161216565b811015610a8f576007915050610a95565b60089150505b919050565b6001600160a01b03811660009081526004602052604081205490610abd83610947565b9050818111610afd5760405162461bcd60e51b8152600401808060200182810382526027815260200180611dde6027913960400191505060405180910390fd5b6001600160a01b03831660009081526006602090815260408083208584529091529020546002111580610b2e575081155b610b695760405162461bcd60e51b8152600401808060200182810382526037815260200180611e8e6037913960400191505060405180910390fd5b6001600160a01b03831660008181526004602090815260409182902060018601908190558251938452908301859052828201819052905190917f767f4cc8b13a4a9eea7c39d0871afa4bb5e33f67bc98177b1e7cedfdddffbda1919081900360600190a16001600160a01b03808516600090815260016020526040902054168015610c80576001600160a01b0381166000908152600660209081526040808320858452909152902054610c2390600163ffffffff61174616565b6001600160a01b0382166000908152600660209081526040808320868452909152808220929092558581522054610c5b906001611704565b6001600160a01b03821660009081526006602090815260408083208884529091529020555b6000610cbb610c8d6117a0565b60008781526005602090815260408083208884529091529020546107db906305f5e10063ffffffff61161216565b90506611c37937e08000610cda8260095461174690919063ffffffff16565b11610dbc57600954610cf2908263ffffffff61174616565b600955600c54604080516340c10f1960e01b81526001600160a01b03898116600483015260248201859052915191909216916340c10f199160448083019260209291908290030181600087803b158015610d4b57600080fd5b505af1158015610d5f573d6000803e3d6000fd5b505050506040513d6020811015610d7557600080fd5b5050604080516001600160a01b03881681526020810183905281517f3ed6d188fb440438e3236c1d3267a75f74a4d9a539c5667823b15763a12083cc929181900390910190a15b505050505050565b600660209081526000928352604080842090915290825290205481565b6001600160a01b038216600090815260026020526040902054829060ff16610e50576001600160a01b0381166000818152600260209081526040808320805460ff191660011790558051938452908301919091528051600080516020611e268339815191529281900390910190a15b610e5b6106f661152a565b610e965760405162461bcd60e51b8152600401808060200182810382526030815260200180611ec56030913960400191505060405180910390fd5b6001600160a01b038316600090815260036020526040902054610ebf908363ffffffff61174616565b6001600160a01b03841660008181526003602090815260409182902093909355805191825291810184905260018183015290517fc7c0548976847e189a14f4769fb9e643c5d46bc8e77dbf2970be501130868ce49181900360600190a1505050565b600e546001600160a01b031681565b6000610631818363ffffffff6118c916565b60046020526000908152604090205481565b610f5f6106f661152a565b610f9a5760405162461bcd60e51b8152600401808060200182810382526030815260200180611ec56030913960400191505060405180910390fd5b828114610fd85760405162461bcd60e51b8152600401808060200182810382526027815260200180611d966027913960400191505060405180910390fd5b60005b8381101561102b57611023858583818110610ff257fe5b905060200201356001600160a01b031684848481811061100e57fe5b905060200201356001600160a01b03166112cb565b600101610fdb565b5050505050565b6001600160a01b038216600090815260026020526040902054829060ff166110a1576001600160a01b0381166000818152600260209081526040808320805460ff191660011790558051938452908301919091528051600080516020611e268339815191529281900390910190a15b6110ac6106f661152a565b6110e75760405162461bcd60e51b8152600401808060200182810382526030815260200180611ec56030913960400191505060405180910390fd5b60006110f16117a0565b9050600061110d6305f5e1006107db868563ffffffff61161216565b6001600160a01b038616600090815260036020526040902054909150611139908263ffffffff61174616565b6001600160a01b03861660008181526003602090815260409182902093909355805191825291810183905260018183015290517fc7c0548976847e189a14f4769fb9e643c5d46bc8e77dbf2970be501130868ce49181900360600190a15050505050565b600c546001600160a01b031681565b6611c37937e0800081565b6001602052600090815260409020546001600160a01b031681565b6001600160a01b038116600090815260046020526040812054816111f584610947565b9050818111801561123257506001600160a01b03841660009081526006602090815260408083208584529091529020546002111580611232575081155b949350505050565b61124a61124561152a565b611930565b565b600d546001600160a01b031681565b6112666106f661152a565b6112a15760405162461bcd60e51b8152600401808060200182810382526030815260200180611ec56030913960400191505060405180910390fd5b6112aa81611978565b50565b600881815481106112ba57fe5b600091825260209091200154905081565b6112d66106f661152a565b6113115760405162461bcd60e51b8152600401808060200182810382526030815260200180611ec56030913960400191505060405180910390fd5b6001600160a01b03821660009081526002602052604090205460ff16156113695760405162461bcd60e51b8152600401808060200182810382526026815260200180611e686026913960400191505060405180910390fd5b806001600160a01b0316826001600160a01b031614156113d0576040805162461bcd60e51b815260206004820152601c60248201527f5065616b5265776172643a2063616e27742072656665722073656c6600000000604482015290519081900360640190fd5b6001600160a01b038216158015906113f057506001600160a01b03811615155b611439576040805162461bcd60e51b81526020600482015260156024820152745065616b5265776172643a2030206164647265737360581b604482015290519081900360640190fd5b6001600160a01b0382811660008181526002602090815260408083208054600160ff1991821681179092559587168085528285208054909716821790965593835283825280832080546001600160a01b0319168617905593825260068152838220828052905291909120546114ad91611746565b6001600160a01b0380831660008181526006602090815260408083208380528252918290209490945580519286168352928201528151600080516020611e26833981519152929181900390910190a15050565b600560209081526000928352604080842090915290825290205481565b600781815481106112ba57fe5b335b90565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526115899085906119c0565b50505050565b600b5460408051631f42340d60e11b81526001600160a01b03848116600483015291516000939290921691633e84681a91602480820192602092909190829003018186803b1580156115e057600080fd5b505afa1580156115f4573d6000803e3d6000fd5b505050506040513d602081101561160a57600080fd5b505192915050565b60008261162157506000610631565b8282028284828161162e57fe5b041461062e5760405162461bcd60e51b8152600401808060200182810382526021815260200180611e056021913960400191505060405180910390fd5b600061062e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611b78565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526116ff9084906119c0565b505050565b600061062e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611c1a565b60008282018381101561062e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600e546040805163a2e6204560e01b815290516000926001600160a01b03169163a2e6204591600480830192602092919082900301818787803b1580156117e657600080fd5b505af11580156117fa573d6000803e3d6000fd5b505050506040513d602081101561181057600080fd5b5050600e54600c5460408051633ddac95360e01b81526001600160a01b0392831660048201526305f5e100602482015290516000939290921691633ddac95391604480820192602092909190829003018186803b15801561187057600080fd5b505afa158015611884573d6000803e3d6000fd5b505050506040513d602081101561189a57600080fd5b50519050806118c4576118bc600a6107db620f4240600363ffffffff61161216565b91505061152c565b905090565b60006001600160a01b0382166119105760405162461bcd60e51b8152600401808060200182810382526022815260200180611e466022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b61194160008263ffffffff611c7416565b6040516001600160a01b038216907f3525e22824a8a7df2c9a6029941c824cf95b6447f1e13d5128fd3826d35afe8b90600090a250565b61198960008263ffffffff611cdb16565b6040516001600160a01b038216907f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f2490600090a250565b6119d2826001600160a01b0316611d5c565b611a23576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310611a615780518252601f199092019160209182019101611a42565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611ac3576040519150601f19603f3d011682016040523d82523d6000602084013e611ac8565b606091505b509150915081611b1f576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b80511561158957808060200190516020811015611b3b57600080fd5b50516115895760405162461bcd60e51b815260040180806020018281038252602a815260200180611ef5602a913960400191505060405180910390fd5b60008183611c045760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611bc9578181015183820152602001611bb1565b50505050905090810190601f168015611bf65780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581611c1057fe5b0495945050505050565b60008184841115611c6c5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611bc9578181015183820152602001611bb1565b505050900390565b611c7e82826118c9565b611cb95760405162461bcd60e51b8152600401808060200182810382526021815260200180611dbd6021913960400191505060405180910390fd5b6001600160a01b0316600090815260209190915260409020805460ff19169055565b611ce582826118c9565b15611d37576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061123257505015159291505056fe5065616b5265776172643a20617272617973206c656e67746820617265206e6f7420657175616c526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c655065616b5265776172643a206361726565722076616c7565206973206e6f7420656e6f75676821536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7798ada70a1cb506dc4591465e1ee9be3fd7a2b6c73ecf3b949009718c9a351519526f6c65733a206163636f756e7420697320746865207a65726f20616464726573735065616b5265776172643a20726566657272656420697320616c7265616479206120757365725065616b5265776172643a20646f776e6c696e657320636f756e7420616e6420726571756972656d656e74206e6f7420706173736564215369676e6572526f6c653a2063616c6c657220646f6573206e6f74206861766520746865205369676e657220726f6c655361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a265627a7a7231582023c04ca584c28613008cc06bd837d2745ff25ecf8c3188f5d6ff51369b1ef57364736f6c63430005110032536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77526f6c65733a206163636f756e7420697320746865207a65726f2061646472657373000000000000000000000000b902891525339c2fd101a5a79a5e7e2fb39e094d0000000000000000000000009733f49d577da2b6705ca173382c0e3cdfff2a48000000000000000000000000630d98424efe0ea27fb1b3ab7741907dffeaad78000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000008fb8b62ad979d833f450e3ede2cebabdeb9ddd85
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101a95760003560e01c8063874c1daf116100f9578063e5c8b03d11610097578063f33a559111610071578063f33a55911461053a578063f454425514610557578063fb1f111c14610585578063fd7f65bd146105a8576101a9565b8063e5c8b03d14610504578063e9cbd8221461050c578063eb12d61e14610514576101a9565b8063c298a69f116100d3578063c298a69f146104a8578063c93f636a146104b0578063d21cacdf146104b8578063db203e6c146104de576101a9565b8063874c1daf146103945780638ef4121f146103ba57806397017cae1461047c576101a9565b8063650f5443116101665780637cf6f53a116101405780637cf6f53a1461030e5780637d49ac361461033a5780637dc0d1d0146103665780637df73e271461036e576101a9565b8063650f5443146102825780636796ec30146102c05780636f8bd036146102e6576101a9565b806309164fe6146101ae57806310f79eb5146101c8578063212c868f1461020a5780633131be901461022e5780634209fff1146102365780635497f9b71461025c575b600080fd5b6101b66105c5565b60408051918252519081900360200190f35b6101f6600480360360408110156101de57600080fd5b506001600160a01b03813581169160200135166105cb565b604080519115158252519081900360200190f35b610212610637565b604080516001600160a01b039092168252519081900360200190f35b610212610646565b6101f66004803603602081101561024c57600080fd5b50356001600160a01b0316610655565b6101b66004803603602081101561027257600080fd5b50356001600160a01b031661066a565b6101b66004803603608081101561029857600080fd5b506001600160a01b03813581169160208101359091169060408101359060600135151561067c565b6101b6600480360360208110156102d657600080fd5b50356001600160a01b0316610947565b61030c600480360360208110156102fc57600080fd5b50356001600160a01b0316610a9a565b005b6101b66004803603604081101561032457600080fd5b506001600160a01b038135169060200135610dc4565b61030c6004803603604081101561035057600080fd5b506001600160a01b038135169060200135610de1565b610212610f21565b6101f66004803603602081101561038457600080fd5b50356001600160a01b0316610f30565b6101b6600480360360208110156103aa57600080fd5b50356001600160a01b0316610f42565b61030c600480360360408110156103d057600080fd5b8101906020810181356401000000008111156103eb57600080fd5b8201836020820111156103fd57600080fd5b8035906020019184602083028401116401000000008311171561041f57600080fd5b91939092909160208101903564010000000081111561043d57600080fd5b82018360208201111561044f57600080fd5b8035906020019184602083028401116401000000008311171561047157600080fd5b509092509050610f54565b61030c6004803603604081101561049257600080fd5b506001600160a01b038135169060200135611032565b61021261119d565b6101b66111ac565b610212600480360360208110156104ce57600080fd5b50356001600160a01b03166111b7565b6101f6600480360360208110156104f457600080fd5b50356001600160a01b03166111d2565b61030c61123a565b61021261124c565b61030c6004803603602081101561052a57600080fd5b50356001600160a01b031661125b565b6101b66004803603602081101561055057600080fd5b50356112ad565b61030c6004803603604081101561056d57600080fd5b506001600160a01b03813581169160200135166112cb565b6101b66004803603604081101561059b57600080fd5b5080359060200135611500565b6101b6600480360360208110156105be57600080fd5b503561151d565b60095481565b6001600160a01b03821660009081526002602052604081205460ff161580156106065750816001600160a01b0316836001600160a01b031614155b801561061a57506001600160a01b03831615155b801561062e57506001600160a01b03821615155b90505b92915050565b600a546001600160a01b031681565b600b546001600160a01b031681565b60026020526000908152604090205460ff1681565b60036020526000908152604090205481565b6001600160a01b038416600090815260026020526040812054859060ff166106eb576001600160a01b0381166000818152600260209081526040808320805460ff191660011790558051938452908301919091528051600080516020611e268339815191529281900390910190a15b6106fb6106f661152a565b610f30565b6107365760405162461bcd60e51b8152600401808060200182810382526030815260200180611ec56030913960400191505060405180910390fd5b846107526001600160a01b03821633308863ffffffff61152f16565b868560005b6001600160a01b038316158015906107725750600860ff8216105b156108ea5760088160ff168154811061078757fe5b906000526020600020015461079b8461158f565b106108c35760006107e76702c68af0bb1400006107db60078560ff16815481106107c157fe5b90600052602060002001548c61161290919063ffffffff16565b9063ffffffff61166b16565b9050828111156107f45750815b61080e6001600160a01b038616858363ffffffff6116ad16565b61081e838263ffffffff61170416565b600c549093506001600160a01b038b811691161415610846576108418482611032565b610866565b600d546001600160a01b038b811691161415610866576108668482610de1565b604080516001600160a01b03808e16825280871660208301528c16818301526060810183905260ff8416608082015290517f83e0d93d1f31c32a251200957cfc5c8dae763ff279427f6cf07b5f1e77f488439181900360a00190a1505b6001600160a01b039283166000908152600160208190526040909120549093169201610757565b86156109155761090a6001600160a01b038516338463ffffffff6116ad16565b50935061093e915050565b600a54610935906001600160a01b0386811691168463ffffffff6116ad16565b60009550505050505b50949350505050565b6001600160a01b038116600090815260036020526040812054610974620f4240606463ffffffff61161216565b811015610985576000915050610a95565b610999620f424060fa63ffffffff61161216565b8110156109aa576001915050610a95565b6109bf620f42406102ee63ffffffff61161216565b8110156109d0576002915050610a95565b6109e5620f42406105dc63ffffffff61161216565b8110156109f6576003915050610a95565b610a0b620f4240610bb863ffffffff61161216565b811015610a1c576004915050610a95565b610a31620f424061271063ffffffff61161216565b811015610a42576005915050610a95565b610a57620f424061c35063ffffffff61161216565b811015610a68576006915050610a95565b610a7e620f4240620249f063ffffffff61161216565b811015610a8f576007915050610a95565b60089150505b919050565b6001600160a01b03811660009081526004602052604081205490610abd83610947565b9050818111610afd5760405162461bcd60e51b8152600401808060200182810382526027815260200180611dde6027913960400191505060405180910390fd5b6001600160a01b03831660009081526006602090815260408083208584529091529020546002111580610b2e575081155b610b695760405162461bcd60e51b8152600401808060200182810382526037815260200180611e8e6037913960400191505060405180910390fd5b6001600160a01b03831660008181526004602090815260409182902060018601908190558251938452908301859052828201819052905190917f767f4cc8b13a4a9eea7c39d0871afa4bb5e33f67bc98177b1e7cedfdddffbda1919081900360600190a16001600160a01b03808516600090815260016020526040902054168015610c80576001600160a01b0381166000908152600660209081526040808320858452909152902054610c2390600163ffffffff61174616565b6001600160a01b0382166000908152600660209081526040808320868452909152808220929092558581522054610c5b906001611704565b6001600160a01b03821660009081526006602090815260408083208884529091529020555b6000610cbb610c8d6117a0565b60008781526005602090815260408083208884529091529020546107db906305f5e10063ffffffff61161216565b90506611c37937e08000610cda8260095461174690919063ffffffff16565b11610dbc57600954610cf2908263ffffffff61174616565b600955600c54604080516340c10f1960e01b81526001600160a01b03898116600483015260248201859052915191909216916340c10f199160448083019260209291908290030181600087803b158015610d4b57600080fd5b505af1158015610d5f573d6000803e3d6000fd5b505050506040513d6020811015610d7557600080fd5b5050604080516001600160a01b03881681526020810183905281517f3ed6d188fb440438e3236c1d3267a75f74a4d9a539c5667823b15763a12083cc929181900390910190a15b505050505050565b600660209081526000928352604080842090915290825290205481565b6001600160a01b038216600090815260026020526040902054829060ff16610e50576001600160a01b0381166000818152600260209081526040808320805460ff191660011790558051938452908301919091528051600080516020611e268339815191529281900390910190a15b610e5b6106f661152a565b610e965760405162461bcd60e51b8152600401808060200182810382526030815260200180611ec56030913960400191505060405180910390fd5b6001600160a01b038316600090815260036020526040902054610ebf908363ffffffff61174616565b6001600160a01b03841660008181526003602090815260409182902093909355805191825291810184905260018183015290517fc7c0548976847e189a14f4769fb9e643c5d46bc8e77dbf2970be501130868ce49181900360600190a1505050565b600e546001600160a01b031681565b6000610631818363ffffffff6118c916565b60046020526000908152604090205481565b610f5f6106f661152a565b610f9a5760405162461bcd60e51b8152600401808060200182810382526030815260200180611ec56030913960400191505060405180910390fd5b828114610fd85760405162461bcd60e51b8152600401808060200182810382526027815260200180611d966027913960400191505060405180910390fd5b60005b8381101561102b57611023858583818110610ff257fe5b905060200201356001600160a01b031684848481811061100e57fe5b905060200201356001600160a01b03166112cb565b600101610fdb565b5050505050565b6001600160a01b038216600090815260026020526040902054829060ff166110a1576001600160a01b0381166000818152600260209081526040808320805460ff191660011790558051938452908301919091528051600080516020611e268339815191529281900390910190a15b6110ac6106f661152a565b6110e75760405162461bcd60e51b8152600401808060200182810382526030815260200180611ec56030913960400191505060405180910390fd5b60006110f16117a0565b9050600061110d6305f5e1006107db868563ffffffff61161216565b6001600160a01b038616600090815260036020526040902054909150611139908263ffffffff61174616565b6001600160a01b03861660008181526003602090815260409182902093909355805191825291810183905260018183015290517fc7c0548976847e189a14f4769fb9e643c5d46bc8e77dbf2970be501130868ce49181900360600190a15050505050565b600c546001600160a01b031681565b6611c37937e0800081565b6001602052600090815260409020546001600160a01b031681565b6001600160a01b038116600090815260046020526040812054816111f584610947565b9050818111801561123257506001600160a01b03841660009081526006602090815260408083208584529091529020546002111580611232575081155b949350505050565b61124a61124561152a565b611930565b565b600d546001600160a01b031681565b6112666106f661152a565b6112a15760405162461bcd60e51b8152600401808060200182810382526030815260200180611ec56030913960400191505060405180910390fd5b6112aa81611978565b50565b600881815481106112ba57fe5b600091825260209091200154905081565b6112d66106f661152a565b6113115760405162461bcd60e51b8152600401808060200182810382526030815260200180611ec56030913960400191505060405180910390fd5b6001600160a01b03821660009081526002602052604090205460ff16156113695760405162461bcd60e51b8152600401808060200182810382526026815260200180611e686026913960400191505060405180910390fd5b806001600160a01b0316826001600160a01b031614156113d0576040805162461bcd60e51b815260206004820152601c60248201527f5065616b5265776172643a2063616e27742072656665722073656c6600000000604482015290519081900360640190fd5b6001600160a01b038216158015906113f057506001600160a01b03811615155b611439576040805162461bcd60e51b81526020600482015260156024820152745065616b5265776172643a2030206164647265737360581b604482015290519081900360640190fd5b6001600160a01b0382811660008181526002602090815260408083208054600160ff1991821681179092559587168085528285208054909716821790965593835283825280832080546001600160a01b0319168617905593825260068152838220828052905291909120546114ad91611746565b6001600160a01b0380831660008181526006602090815260408083208380528252918290209490945580519286168352928201528151600080516020611e26833981519152929181900390910190a15050565b600560209081526000928352604080842090915290825290205481565b600781815481106112ba57fe5b335b90565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526115899085906119c0565b50505050565b600b5460408051631f42340d60e11b81526001600160a01b03848116600483015291516000939290921691633e84681a91602480820192602092909190829003018186803b1580156115e057600080fd5b505afa1580156115f4573d6000803e3d6000fd5b505050506040513d602081101561160a57600080fd5b505192915050565b60008261162157506000610631565b8282028284828161162e57fe5b041461062e5760405162461bcd60e51b8152600401808060200182810382526021815260200180611e056021913960400191505060405180910390fd5b600061062e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611b78565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526116ff9084906119c0565b505050565b600061062e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611c1a565b60008282018381101561062e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600e546040805163a2e6204560e01b815290516000926001600160a01b03169163a2e6204591600480830192602092919082900301818787803b1580156117e657600080fd5b505af11580156117fa573d6000803e3d6000fd5b505050506040513d602081101561181057600080fd5b5050600e54600c5460408051633ddac95360e01b81526001600160a01b0392831660048201526305f5e100602482015290516000939290921691633ddac95391604480820192602092909190829003018186803b15801561187057600080fd5b505afa158015611884573d6000803e3d6000fd5b505050506040513d602081101561189a57600080fd5b50519050806118c4576118bc600a6107db620f4240600363ffffffff61161216565b91505061152c565b905090565b60006001600160a01b0382166119105760405162461bcd60e51b8152600401808060200182810382526022815260200180611e466022913960400191505060405180910390fd5b506001600160a01b03166000908152602091909152604090205460ff1690565b61194160008263ffffffff611c7416565b6040516001600160a01b038216907f3525e22824a8a7df2c9a6029941c824cf95b6447f1e13d5128fd3826d35afe8b90600090a250565b61198960008263ffffffff611cdb16565b6040516001600160a01b038216907f47d1c22a25bb3a5d4e481b9b1e6944c2eade3181a0a20b495ed61d35b5323f2490600090a250565b6119d2826001600160a01b0316611d5c565b611a23576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b60208310611a615780518252601f199092019160209182019101611a42565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611ac3576040519150601f19603f3d011682016040523d82523d6000602084013e611ac8565b606091505b509150915081611b1f576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b80511561158957808060200190516020811015611b3b57600080fd5b50516115895760405162461bcd60e51b815260040180806020018281038252602a815260200180611ef5602a913960400191505060405180910390fd5b60008183611c045760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611bc9578181015183820152602001611bb1565b50505050905090810190601f168015611bf65780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581611c1057fe5b0495945050505050565b60008184841115611c6c5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611bc9578181015183820152602001611bb1565b505050900390565b611c7e82826118c9565b611cb95760405162461bcd60e51b8152600401808060200182810382526021815260200180611dbd6021913960400191505060405180910390fd5b6001600160a01b0316600090815260209190915260409020805460ff19169055565b611ce582826118c9565b15611d37576040805162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c6500604482015290519081900360640190fd5b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061123257505015159291505056fe5065616b5265776172643a20617272617973206c656e67746820617265206e6f7420657175616c526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c655065616b5265776172643a206361726565722076616c7565206973206e6f7420656e6f75676821536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7798ada70a1cb506dc4591465e1ee9be3fd7a2b6c73ecf3b949009718c9a351519526f6c65733a206163636f756e7420697320746865207a65726f20616464726573735065616b5265776172643a20726566657272656420697320616c7265616479206120757365725065616b5265776172643a20646f776e6c696e657320636f756e7420616e6420726571756972656d656e74206e6f7420706173736564215369676e6572526f6c653a2063616c6c657220646f6573206e6f74206861766520746865205369676e657220726f6c655361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a265627a7a7231582023c04ca584c28613008cc06bd837d2745ff25ecf8c3188f5d6ff51369b1ef57364736f6c63430005110032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b902891525339c2fd101a5a79a5e7e2fb39e094d0000000000000000000000009733f49d577da2b6705ca173382c0e3cdfff2a48000000000000000000000000630d98424efe0ea27fb1b3ab7741907dffeaad78000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000008fb8b62ad979d833f450e3ede2cebabdeb9ddd85
-----Decoded View---------------
Arg [0] : _marketPeakWallet (address): 0xb902891525339c2fD101A5a79a5E7e2Fb39E094D
Arg [1] : _peakStaking (address): 0x9733f49D577dA2b6705cA173382C0e3CdFff2A48
Arg [2] : _peakToken (address): 0x630d98424eFe0Ea27fB1b3Ab7741907DFFEaAd78
Arg [3] : _stablecoin (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [4] : _oracle (address): 0x8FB8b62AD979D833F450e3eDe2CebaBDeb9DDD85
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000b902891525339c2fd101a5a79a5e7e2fb39e094d
Arg [1] : 0000000000000000000000009733f49d577da2b6705ca173382c0e3cdfff2a48
Arg [2] : 000000000000000000000000630d98424efe0ea27fb1b3ab7741907dffeaad78
Arg [3] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [4] : 0000000000000000000000008fb8b62ad979d833f450e3ede2cebabdeb9ddd85
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.