编译器
0.6.12+commit.27d51765
文件 1 的 18:Address.sol
pragma solidity ^0.6.2;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return _functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
return _functionCallWithValue(target, data, value, errorMessage);
}
function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 18:Context.sol
pragma solidity ^0.6.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 3 的 18:IDvd.sol
pragma solidity ^0.6.12;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
interface IDvd is IERC20 {
function mint(address account, uint256 amount) external;
function burn(address account, uint256 amount) external;
function increaseShareholderPoint(address account, uint256 amount) external;
function decreaseShareholderPoint(address account, uint256 amount) external;
function shareholderPointOf(address account) external view returns (uint256);
function totalShareholderPoint() external view returns (uint256);
}
文件 4 的 18:IERC20.sol
pragma solidity ^0.6.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 5 的 18:ILordOfCoin.sol
pragma solidity ^0.6.12;
interface ILordOfCoin {
function marketOpenTime() external view returns (uint256);
function dvd() external view returns (address);
function sdvd() external view returns (address);
function sdvdEthPairAddress() external view returns (address);
function buy(uint256 musdAmount) external returns (uint256 recipientDVD, uint256 marketTax, uint256 curveTax, uint256 taxedDVD);
function buyTo(address recipient, uint256 musdAmount) external returns (uint256 recipientDVD, uint256 marketTax, uint256 curveTax, uint256 taxedDVD);
function buyFromETH() payable external returns (uint256 recipientDVD, uint256 marketTax, uint256 curveTax, uint256 taxedDVD);
function sell(uint256 dvdAmount) external returns (uint256 returnedMUSD, uint256 marketTax, uint256 curveTax, uint256 taxedDVD);
function sellTo(address recipient, uint256 dvdAmount) external returns (uint256 returnedMUSD, uint256 marketTax, uint256 curveTax, uint256 taxedDVD);
function sellToETH(uint256 dvdAmount) external returns (uint256 returnedETH, uint256 returnedMUSD, uint256 marketTax, uint256 curveTax, uint256 taxedDVD);
function claimDividend() external returns (uint256 net, uint256 fee);
function claimDividendTo(address recipient) external returns (uint256 net, uint256 fee);
function claimDividendETH() external returns (uint256 net, uint256 fee, uint256 receivedETH);
function checkSnapshot() external;
function releaseTreasury() external;
function depositTradingProfit(uint256 amount) external;
}
文件 6 的 18:ISDvd.sol
pragma solidity ^0.6.12;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
interface ISDvd is IERC20 {
function mint(address account, uint256 amount) external;
function burn(address account, uint256 amount) external;
function setMinter(address account, bool value) external;
function setNoFeeAddress(address account, bool value) external;
function setPairAddress(address _pairAddress) external;
function snapshot() external returns (uint256);
function syncPairTokenTotalSupply() external returns (bool isPairTokenBurned);
}
文件 7 的 18:ITreasury.sol
pragma solidity ^0.6.12;
interface ITreasury {
function release() external;
}
文件 8 的 18:IUniswapV2Factory.sol
pragma solidity >=0.5.0;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function migrator() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
function setMigrator(address) external;
}
文件 9 的 18:IUniswapV2Pair.sol
pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
文件 10 的 18:IUniswapV2Router01.sol
pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
文件 11 的 18:IUniswapV2Router02.sol
pragma solidity >=0.6.2;
import './IUniswapV2Router01.sol';
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}
文件 12 的 18:Math.sol
pragma solidity ^0.6.0;
library Math {
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
文件 13 的 18:Ownable.sol
pragma solidity ^0.6.0;
import "../GSN/Context.sol";
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 14 的 18:Pool.sol
pragma solidity ^0.6.12;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/ILordOfCoin.sol";
import "./interfaces/IDvd.sol";
import "./interfaces/ISDvd.sol";
import "./interfaces/ITreasury.sol";
abstract contract Pool is ReentrancyGuard, Ownable {
using SafeMath for uint256;
using SafeERC20 for IERC20;
event Staked(address indexed sender, address indexed recipient, uint256 amount);
event Withdrawn(address indexed sender, address indexed recipient, uint256 amount);
event Claimed(address indexed sender, address indexed recipient, uint256 net, uint256 tax, uint256 total);
event Halving(uint256 amount);
address public stakedToken;
ISDvd public sdvd;
bool public isFarmOpen = false;
uint256 public farmOpenTime;
uint256 public rewardAllocation;
uint256 public rewardRate;
uint256 public rewardDuration = 1460 days;
uint256 public lastUpdateTime;
uint256 public rewardPerTokenStored;
uint256 public finishTime;
uint256 public bonusRewardAllocation;
uint256 public bonusRewardRate;
uint256 public bonusRewardDuration = 1 days;
uint256 public bonusLastUpdateTime;
uint256 public bonusRewardPerTokenStored;
uint256 public bonusRewardFinishTime;
struct AccountInfo {
uint256 balance;
uint256 reward;
uint256 rewardPerTokenPaid;
uint256 bonusReward;
uint256 bonusRewardPerTokenPaid;
}
mapping(address => AccountInfo) public accountInfos;
uint256 private _totalSupply;
uint256 public totalRewardMinted;
address controller;
address poolTreasury;
constructor(address _poolTreasury, uint256 _farmOpenTime) public {
poolTreasury = _poolTreasury;
farmOpenTime = _farmOpenTime;
}
modifier onlyController {
require(msg.sender == controller, 'Controller only');
_;
}
modifier onlyPoolTreasury {
require(msg.sender == poolTreasury, 'Treasury only');
_;
}
modifier farmOpen {
require(isFarmOpen, 'Farm not open');
_;
}
function init(address _controller, address _stakedToken) external onlyOwner {
controller = _controller;
stakedToken = _stakedToken;
sdvd = ISDvd(ILordOfCoin(_controller).sdvd());
renounceOwnership();
}
function distributeBonusRewards(uint256 amount) external onlyPoolTreasury {
bonusRewardAllocation = amount;
bonusRewardRate = bonusRewardAllocation.div(bonusRewardDuration);
bonusRewardFinishTime = block.timestamp.add(bonusRewardDuration);
bonusLastUpdateTime = block.timestamp;
}
function stake(uint256 amount) external nonReentrant {
_stake(msg.sender, msg.sender, amount);
}
function stakeTo(address recipient, uint256 amount) external nonReentrant {
_stake(msg.sender, recipient, amount);
}
function withdraw(uint256 amount) external nonReentrant farmOpen {
_withdraw(msg.sender, msg.sender, amount);
}
function withdrawTo(address recipient, uint256 amount) external nonReentrant farmOpen {
_withdraw(msg.sender, recipient, amount);
}
function claimReward() external nonReentrant farmOpen returns(uint256, uint256, uint256) {
return _claimReward(msg.sender, msg.sender);
}
function claimRewardTo(address recipient) external nonReentrant farmOpen returns(uint256, uint256, uint256) {
return _claimReward(msg.sender, recipient);
}
function _updateReward(address account) internal {
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = lastTimeRewardApplicable();
if (account != address(0)) {
accountInfos[account].reward = earned(account);
accountInfos[account].rewardPerTokenPaid = rewardPerTokenStored;
}
}
function _updateBonusReward(address account) internal {
bonusRewardPerTokenStored = bonusRewardPerToken();
bonusLastUpdateTime = lastTimeBonusRewardApplicable();
if (account != address(0)) {
accountInfos[account].bonusReward = bonusEarned(account);
accountInfos[account].bonusRewardPerTokenPaid = bonusRewardPerTokenStored;
}
}
function _stake(address sender, address recipient, uint256 amount) internal virtual {
_checkOpenFarm();
_checkHalving();
_updateReward(recipient);
_updateBonusReward(recipient);
_notifyController();
require(amount > 0, 'Cannot stake 0');
IERC20(stakedToken).safeTransferFrom(sender, address(this), amount);
_totalSupply = _totalSupply.add(amount);
accountInfos[recipient].balance = accountInfos[recipient].balance.add(amount);
emit Staked(sender, recipient, amount);
}
function _withdraw(address sender, address recipient, uint256 amount) internal virtual {
_checkHalving();
_updateReward(sender);
_updateBonusReward(sender);
_notifyController();
require(amount > 0, 'Cannot withdraw 0');
require(accountInfos[sender].balance >= amount, 'Insufficient balance');
_totalSupply = _totalSupply.sub(amount);
accountInfos[sender].balance = accountInfos[sender].balance.sub(amount);
IERC20(stakedToken).safeTransfer(recipient, amount);
emit Withdrawn(sender, recipient, amount);
}
function _claimReward(address sender, address recipient) internal virtual returns(uint256 totalNetReward, uint256 totalTaxReward, uint256 totalReward) {
_checkHalving();
_updateReward(sender);
_updateBonusReward(sender);
_notifyController();
uint256 reward = accountInfos[sender].reward;
uint256 bonusReward = accountInfos[sender].bonusReward;
totalReward = reward.add(bonusReward);
require(totalReward > 0, 'No reward to claim');
if (reward > 0) {
accountInfos[sender].reward = 0;
uint256 tax = reward.div(claimRewardTaxDenominator());
uint256 net = reward.sub(tax);
sdvd.mint(recipient, net);
sdvd.mint(address(poolTreasury), tax);
totalNetReward = totalNetReward.add(net);
totalTaxReward = totalTaxReward.add(tax);
totalRewardMinted = totalRewardMinted.add(reward);
}
if (bonusReward > 0) {
accountInfos[sender].bonusReward = 0;
uint256 balance = sdvd.balanceOf(address(this));
if (bonusReward > balance) {
bonusReward = balance;
}
uint256 tax = bonusReward.div(claimRewardTaxDenominator());
uint256 net = bonusReward.sub(tax);
IERC20(sdvd).safeTransfer(recipient, net);
IERC20(sdvd).safeTransfer(address(poolTreasury), tax);
totalNetReward = totalNetReward.add(net);
totalTaxReward = totalTaxReward.add(tax);
}
if (totalReward > 0) {
emit Claimed(sender, recipient, totalNetReward, totalTaxReward, totalReward);
}
}
function _checkOpenFarm() internal {
require(farmOpenTime <= block.timestamp, 'Farm not open');
if (!isFarmOpen) {
isFarmOpen = true;
lastUpdateTime = block.timestamp;
finishTime = block.timestamp.add(rewardDuration);
rewardRate = rewardAllocation.div(rewardDuration);
bonusLastUpdateTime = block.timestamp;
bonusRewardFinishTime = block.timestamp.add(bonusRewardDuration);
bonusRewardRate = bonusRewardAllocation.div(bonusRewardDuration);
}
}
function _checkHalving() internal {
if (block.timestamp >= finishTime) {
rewardAllocation = rewardAllocation.div(2);
rewardRate = rewardAllocation.div(rewardDuration);
finishTime = block.timestamp.add(rewardDuration);
lastUpdateTime = block.timestamp;
emit Halving(rewardAllocation);
}
}
function _notifyController() internal {
ILordOfCoin(controller).checkSnapshot();
ILordOfCoin(controller).releaseTreasury();
}
function totalSupply() external view returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) external view returns (uint256) {
return accountInfos[account].balance;
}
function fullEarned(address account) external view returns (uint256) {
return earned(account).add(bonusEarned(account));
}
function fullRewardRate() external view returns (uint256) {
return rewardRate.add(bonusRewardRate);
}
function claimRewardTaxDenominator() public view returns (uint256) {
if (block.timestamp < farmOpenTime.add(365 days)) {
return 2;
} else if (block.timestamp < farmOpenTime.add(730 days)) {
return 3;
} else if (block.timestamp < farmOpenTime.add(1095 days)) {
return 4;
} else if (block.timestamp < farmOpenTime.add(1460 days)) {
return 5;
} else {
return 10;
}
}
function lastTimeRewardApplicable() public view returns (uint256) {
return Math.min(block.timestamp, finishTime);
}
function rewardPerToken() public view returns (uint256) {
if (_totalSupply == 0) {
return rewardPerTokenStored;
}
return rewardPerTokenStored.add(
lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(_totalSupply)
);
}
function earned(address account) public view returns (uint256) {
return accountInfos[account].balance.mul(
rewardPerToken().sub(accountInfos[account].rewardPerTokenPaid)
)
.div(1e18)
.add(accountInfos[account].reward);
}
function lastTimeBonusRewardApplicable() public view returns (uint256) {
return Math.min(block.timestamp, bonusRewardFinishTime);
}
function bonusRewardPerToken() public view returns (uint256) {
if (_totalSupply == 0) {
return bonusRewardPerTokenStored;
}
return bonusRewardPerTokenStored.add(
lastTimeBonusRewardApplicable().sub(bonusLastUpdateTime).mul(bonusRewardRate).mul(1e18).div(_totalSupply)
);
}
function bonusEarned(address account) public view returns (uint256) {
return accountInfos[account].balance.mul(
bonusRewardPerToken().sub(accountInfos[account].bonusRewardPerTokenPaid)
)
.div(1e18)
.add(accountInfos[account].bonusReward);
}
}
文件 15 的 18:ReentrancyGuard.sol
pragma solidity ^0.6.0;
contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 16 的 18:SDvdEthPool.sol
pragma solidity ^0.6.12;
import "./uniswapv2/interfaces/IUniswapV2Router02.sol";
import "./uniswapv2/interfaces/IUniswapV2Pair.sol";
import "./uniswapv2/interfaces/IUniswapV2Factory.sol";
import "./interfaces/IDvd.sol";
import "./Pool.sol";
contract SDvdEthPool is Pool {
event StakedETH(address indexed account, uint256 amount);
event ClaimedAndStaked(address indexed account, uint256 amount);
IUniswapV2Router02 uniswapRouter;
IUniswapV2Factory uniswapFactory;
address weth;
bool public isLGEActive = true;
uint256 public LGE_INITIAL_DEPOSIT_CAP = 5 ether;
uint256 public LGE_HARD_CAP = 200 ether;
uint256 public LGE_INITIAL_PRICE_MULTIPLIER = 2;
constructor(address _poolTreasury, address _uniswapRouter, uint256 _farmOpenTime) public Pool(_poolTreasury, _farmOpenTime) {
rewardAllocation = 240000 * 1e18;
rewardAllocation = rewardAllocation.sub(LGE_HARD_CAP.div(2));
uniswapRouter = IUniswapV2Router02(_uniswapRouter);
uniswapFactory = IUniswapV2Factory(uniswapRouter.factory());
weth = uniswapRouter.WETH();
}
receive() external payable {
}
function stakeETH() external payable nonReentrant {
_stakeETH(msg.value);
}
function stakeSDVD(uint256 amountToken) external payable nonReentrant farmOpen {
require(isLGEActive == false, 'LGE still active');
uint256 pairSDVDBalance = IERC20(sdvd).balanceOf(stakedToken);
uint256 pairETHBalance = IERC20(weth).balanceOf(stakedToken);
uint256 amountETH = amountToken.mul(pairETHBalance).div(pairSDVDBalance);
require(msg.value >= amountETH, 'Not enough ETH');
uint256 excessETH = msg.value.sub(amountETH);
if (excessETH > 0) {
msg.sender.transfer(excessETH);
}
IERC20(sdvd).safeTransferFrom(msg.sender, address(this), amountToken);
IERC20(sdvd).approve(address(uniswapRouter), amountToken);
(,, uint256 liquidity) = uniswapRouter.addLiquidityETH{value : amountETH}(address(sdvd), amountToken, 0, 0, address(this), block.timestamp.add(30 minutes));
IERC20(stakedToken).approve(address(this), liquidity);
_stake(address(this), msg.sender, liquidity);
}
function claimRewardAndStake() external nonReentrant farmOpen {
require(isLGEActive == false, 'LGE still active');
(uint256 totalNetReward,,) = _claimReward(msg.sender, address(this));
uint256 swapAmountSDVD = totalNetReward.div(2);
address[] memory path = new address[](2);
path[0] = address(sdvd);
path[1] = weth;
IERC20(sdvd).approve(address(uniswapRouter), swapAmountSDVD);
uint256[] memory amounts = uniswapRouter.swapExactTokensForETH(swapAmountSDVD, 0, path, address(this), block.timestamp.add(30 minutes));
uint256 amountETHReceived = amounts[1];
uint256 pairSDVDBalance = IERC20(sdvd).balanceOf(stakedToken);
uint256 pairETHBalance = IERC20(weth).balanceOf(stakedToken);
uint256 amountSDVD = totalNetReward.sub(swapAmountSDVD);
uint256 amountETH = amountSDVD.mul(pairETHBalance).div(pairSDVDBalance);
if (amountETH > amountETHReceived) {
amountETH = amountETHReceived;
uint256 amountSDVDRequired = amountETH.mul(pairSDVDBalance).div(pairETHBalance);
if (amountSDVD > amountSDVDRequired) {
IERC20(sdvd).safeTransfer(msg.sender, amountSDVD.sub(amountSDVDRequired));
}
amountSDVD = amountSDVDRequired;
}
else if (amountETHReceived > amountETH) {
msg.sender.transfer(amountETHReceived.sub(amountETH));
}
IERC20(sdvd).approve(address(uniswapRouter), amountSDVD);
(,, uint256 liquidity) = uniswapRouter.addLiquidityETH{value : amountETH}(address(sdvd), amountSDVD, 0, 0, address(this), block.timestamp.add(30 minutes));
IERC20(stakedToken).approve(address(this), liquidity);
_stake(address(this), msg.sender, liquidity);
emit ClaimedAndStaked(msg.sender, liquidity);
}
function _stakeETH(uint256 value) internal {
if (isLGEActive) {
uint256 pairSDVDBalance = IERC20(sdvd).balanceOf(stakedToken);
if (pairSDVDBalance == 0) {
require(msg.value <= LGE_INITIAL_DEPOSIT_CAP, 'Initial deposit cap reached');
}
uint256 pairETHBalance = IERC20(weth).balanceOf(stakedToken);
uint256 amountETH = msg.value;
uint256 amountSDVD = pairSDVDBalance == 0 ? amountETH.mul(LGE_INITIAL_PRICE_MULTIPLIER) : amountETH.mul(pairSDVDBalance).div(pairETHBalance);
uint256 excessETH = 0;
if (pairSDVDBalance.add(amountSDVD) > LGE_HARD_CAP) {
uint256 excessToken = pairSDVDBalance.add(amountSDVD).sub(LGE_HARD_CAP);
amountSDVD = amountSDVD.sub(excessToken);
excessETH = excessToken.mul(pairETHBalance).div(pairSDVDBalance);
amountETH = amountETH.sub(excessETH);
}
ISDvd(sdvd).mint(address(this), amountSDVD);
IERC20(sdvd).approve(address(uniswapRouter), amountSDVD);
(,, uint256 liquidity) = uniswapRouter.addLiquidityETH{value : amountETH}(address(sdvd), amountSDVD, 0, 0, address(this), block.timestamp.add(30 minutes));
pairSDVDBalance = IERC20(sdvd).balanceOf(stakedToken);
isLGEActive = pairSDVDBalance < LGE_HARD_CAP;
IERC20(stakedToken).approve(address(this), liquidity);
_stake(address(this), msg.sender, liquidity);
if (excessETH > 0) {
_stakeETH(excessETH);
}
} else {
uint256 amountETH = value.div(2);
address[] memory path = new address[](2);
path[0] = weth;
path[1] = address(sdvd);
uint256[] memory amounts = uniswapRouter.swapExactETHForTokens{value : amountETH}(
0,
path,
address(this),
block.timestamp.add(30 minutes)
);
uint256 amountSDVDReceived = amounts[1];
uint256 pairSDVDBalance = IERC20(sdvd).balanceOf(stakedToken);
uint256 pairETHBalance = IERC20(weth).balanceOf(stakedToken);
amountETH = value.sub(amountETH);
uint256 amountSDVD = amountETH.mul(pairSDVDBalance).div(pairETHBalance);
if (amountSDVD > amountSDVDReceived) {
amountSDVD = amountSDVDReceived;
uint256 amountETHRequired = amountSDVD.mul(pairETHBalance).div(pairSDVDBalance);
if (amountETH > amountETHRequired) {
msg.sender.transfer(amountETH.sub(amountETHRequired));
}
amountETH = amountETHRequired;
}
else if (amountSDVDReceived > amountSDVD) {
IERC20(sdvd).transfer(msg.sender, amountSDVDReceived.sub(amountSDVD));
}
IERC20(sdvd).approve(address(uniswapRouter), amountSDVD);
(,, uint256 liquidity) = uniswapRouter.addLiquidityETH{value : amountETH}(address(sdvd), amountSDVD, 0, 0, address(this), block.timestamp.add(30 minutes));
ISDvd(sdvd).syncPairTokenTotalSupply();
IERC20(stakedToken).approve(address(this), liquidity);
_stake(address(this), msg.sender, liquidity);
}
emit StakedETH(msg.sender, msg.value);
}
}
文件 17 的 18:SafeERC20.sol
pragma solidity ^0.6.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 18 的 18:SafeMath.sol
pragma solidity ^0.6.0;
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
{
"compilationTarget": {
"contracts/SDvdEthPool.sol": "SDvdEthPool"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_poolTreasury","type":"address"},{"internalType":"address","name":"_uniswapRouter","type":"address"},{"internalType":"uint256","name":"_farmOpenTime","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"net","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tax","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"total","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimedAndStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Halving","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakedETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"LGE_HARD_CAP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LGE_INITIAL_DEPOSIT_CAP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LGE_INITIAL_PRICE_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountInfos","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"},{"internalType":"uint256","name":"rewardPerTokenPaid","type":"uint256"},{"internalType":"uint256","name":"bonusReward","type":"uint256"},{"internalType":"uint256","name":"bonusRewardPerTokenPaid","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"bonusEarned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusLastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusRewardAllocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusRewardDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusRewardFinishTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusRewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusRewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusRewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimRewardAndStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimRewardTaxDenominator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"claimRewardTo","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"distributeBonusRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"earned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"farmOpenTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finishTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"fullEarned","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullRewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_stakedToken","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isFarmOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isLGEActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastTimeBonusRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardAllocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerTokenStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sdvd","outputs":[{"internalType":"contract ISDvd","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"}],"name":"stakeSDVD","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stakeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakedToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRewardMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]