编译器
0.8.20+commit.a1b79de6
文件 1 的 7:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 2 的 7:FARM.sol
pragma solidity ^0.8.20;
import '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol';
import '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract FARM is Ownable, ReentrancyGuard {
struct Deposit {
uint256 amount;
uint256 excluded;
uint256 excludedLpRewards;
}
IUniswapV2Router02 public router;
IERC20 public rice;
IERC20 public lpToken;
IERC20 public weth;
uint256 public PRECISION = 1e18;
uint256 public rewardsPerSecond;
uint256 public rewardsPerDeposit;
uint256 public rewardPeriodStart;
uint256 public rewardsUpdatedAt;
uint256 public rewardPeriodEnd;
uint256 public rewardedLpPerDeposit;
uint256 public totalDeposited;
uint256 public totalLpRewards;
uint256 public waitingPeriod;
uint256 public rewardPeriod;
mapping(address => Deposit) public deposits;
event Deposited(address indexed depositor, uint256 amount);
event Withdrawn(address indexed depositor, uint256 amount);
event Harvested(address indexed depositor, uint256 rewards);
event HarvestedLP(address indexed depositor, uint256 rewards);
event LpTokensRewarded(address indexed user, uint256 rewards, uint256 totalDeposits, uint256 senderDeposits);
struct UserInfo {
uint256 totalDeposited;
uint256 rewardPeriodStart;
uint256 rewardPeriodEnd;
uint256 rewardsPerSecond;
address lpTokenAddress;
uint256 userDepositAmount;
uint256 userLpBalance;
uint256 userLpApproved;
uint256 amountToHarvest;
uint256 lpToHarvest;
uint256 currentTime;
uint256 ricePerEth;
uint256 lpPerEth;
}
constructor(uint256 _rewardPeriod, uint256 _waitingPeriod) {
waitingPeriod = _waitingPeriod;
rewardPeriod = _rewardPeriod;
}
function getInfo(address user) public view returns (UserInfo memory) {
UserInfo memory info = UserInfo({
totalDeposited: totalDeposited,
rewardPeriodStart: rewardPeriodStart,
rewardPeriodEnd: rewardPeriodEnd,
rewardsPerSecond: rewardsPerSecond,
lpTokenAddress: address(lpToken),
currentTime: block.timestamp,
userDepositAmount: 0,
amountToHarvest: 0,
userLpApproved: 0,
userLpBalance: 0,
lpToHarvest: 0,
ricePerEth: 0,
lpPerEth: 0
});
if (address(lpToken) != address(0)) {
info.lpPerEth = lpPerEth();
info.ricePerEth = ricePerEth();
}
if (user != address(0) && rewardPeriodStart > 0) {
info.userLpApproved = lpToken.allowance(user, address(this));
info.userDepositAmount = deposits[user].amount;
info.amountToHarvest = allocatedAmount(user);
info.userLpBalance = lpToken.balanceOf(user);
info.lpToHarvest = allocatedLpAmount(user);
}
return info;
}
function lpPerEth() public view returns (uint256) {
uint256 lpRiceBalance = rice.balanceOf(address(lpToken));
uint256 lpEthBalance = weth.balanceOf(address(lpToken));
uint256 lpTotalSupply = lpToken.totalSupply();
uint256 _ricePerEth = ricePerEth();
if (_ricePerEth > 0) {
uint256 riceValue = 10**18 * lpRiceBalance / _ricePerEth;
return 10**18 * lpTotalSupply / (riceValue + (10**18 * lpEthBalance));
} else return 0;
}
function ricePerEth() public view returns (uint256) {
address[] memory path = new address[](2);
path[0] = address(weth);
path[1] = address(rice);
uint256[] memory amountsOut = router.getAmountsOut(10**18, path);
return amountsOut[1];
}
function setRiceAddress(IERC20 _rice) external onlyOwner {
transferOwnership(address(_rice));
rice = _rice;
}
function activateRewards(address _uniswapPair, address _weth, address _router) external onlyOwner {
require(address(lpToken) == address(0), "Rewards already activated");
router = IUniswapV2Router02(_router);
lpToken = IERC20(_uniswapPair);
weth = IERC20(_weth);
rewardPeriodStart = block.timestamp + waitingPeriod;
rewardPeriodEnd = rewardPeriodStart + rewardPeriod;
rewardsUpdatedAt = rewardPeriodStart;
rewardsPerSecond = PRECISION * rice.balanceOf(address(this)) / rewardPeriod;
}
function deposit(uint256 amount) external nonReentrant {
require(rewardPeriodStart <= block.timestamp, 'Depositing is not yet enabled');
require(amount > 0, "Cannot deposit 0");
lpToken.transferFrom(msg.sender, address(this), amount);
_harvest();
if (deposits[msg.sender].amount > 0 && amount < 5 * deposits[msg.sender].amount / 100)
_applyHarvestTax();
deposits[msg.sender].amount += amount;
totalDeposited += amount;
emit Deposited(msg.sender, amount);
}
function withdraw(uint256 amount) external nonReentrant {
require(amount > 0, "Cannot withdraw 0");
require(deposits[msg.sender].amount >= amount, "Insufficient deposit");
_harvest();
if (amount < 5 * deposits[msg.sender].amount / 100)
_applyHarvestTax();
uint256 rewards = 0;
if (totalDeposited > amount)
rewards = amount * 5 / 100;
deposits[msg.sender].amount -= amount;
totalDeposited -= amount;
if (totalDeposited - deposits[msg.sender].amount > 0) {
rewardedLpPerDeposit += PRECISION * rewards / (totalDeposited - deposits[msg.sender].amount);
emit LpTokensRewarded(msg.sender, rewards, totalDeposited, deposits[msg.sender].amount);
totalLpRewards += rewards;
amount -= rewards;
}
deposits[msg.sender].excludedLpRewards = rewardedLpPerDeposit;
lpToken.transfer(msg.sender, amount);
emit Withdrawn(msg.sender, amount);
}
function harvest() external nonReentrant {
_harvest();
_applyHarvestTax();
}
function _applyHarvestTax() internal {
if (totalDeposited <= deposits[msg.sender].amount) return;
uint256 rewards = deposits[msg.sender].amount * 5 / 1000;
rewardedLpPerDeposit += PRECISION * rewards / (totalDeposited - deposits[msg.sender].amount);
emit LpTokensRewarded(msg.sender, rewards, totalDeposited, deposits[msg.sender].amount);
deposits[msg.sender].excludedLpRewards = rewardedLpPerDeposit;
deposits[msg.sender].amount -= rewards;
totalDeposited -= rewards;
totalLpRewards += rewards;
}
function _harvestLP() internal {
uint256 rewards = allocatedLpAmount(msg.sender);
deposits[msg.sender].excludedLpRewards = rewardedLpPerDeposit;
if (rewards > 0) {
lpToken.transfer(msg.sender, rewards);
emit HarvestedLP(msg.sender, rewards);
}
}
function _harvest() internal {
_harvestLP();
uint256 rewards = allocatedAmount(msg.sender);
rewardsPerDeposit += _currentRewardsPerDeposit();
deposits[msg.sender].excluded = rewardsPerDeposit;
rewardsUpdatedAt = block.timestamp;
if (rewards > 0) {
rice.transfer(msg.sender, rewards);
emit Harvested(msg.sender, rewards);
}
}
function allocatedLpAmount(address user) public view returns (uint256) {
return deposits[user].amount * (rewardedLpPerDeposit - deposits[user].excludedLpRewards) / PRECISION;
}
function allocatedAmount(address user) public view returns (uint256) {
if (totalDeposited == 0) return 0;
uint256 currentAllocation = currentAllocationPeriod() * rewardsPerSecond * deposits[user].amount / totalDeposited;
uint256 previousAllocation = deposits[user].amount * (rewardsPerDeposit - deposits[user].excluded);
return (previousAllocation + currentAllocation) / PRECISION;
}
function currentAllocationPeriod() public view returns (uint256) {
uint256 currentPeriodEnd = block.timestamp > rewardPeriodEnd ? rewardPeriodEnd : block.timestamp;
return currentPeriodEnd - rewardsUpdatedAt;
}
function _currentRewardsPerDeposit() private view returns (uint256) {
if (totalDeposited == 0) return 0;
return (currentAllocationPeriod() * rewardsPerSecond / totalDeposited);
}
}
文件 3 的 7:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, 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 from, address to, uint256 amount) external returns (bool);
}
文件 4 的 7: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);
}
文件 5 的 7: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;
}
文件 6 的 7:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 7 的 7:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
{
"compilationTarget": {
"project:/contracts/FARM.sol": "FARM"
},
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"uint256","name":"_rewardPeriod","type":"uint256"},{"internalType":"uint256","name":"_waitingPeriod","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"Harvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"}],"name":"HarvestedLP","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalDeposits","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"senderDeposits","type":"uint256"}],"name":"LpTokensRewarded","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":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_uniswapPair","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_router","type":"address"}],"name":"activateRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"allocatedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"allocatedLpAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentAllocationPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"deposits","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"excluded","type":"uint256"},{"internalType":"uint256","name":"excludedLpRewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getInfo","outputs":[{"components":[{"internalType":"uint256","name":"totalDeposited","type":"uint256"},{"internalType":"uint256","name":"rewardPeriodStart","type":"uint256"},{"internalType":"uint256","name":"rewardPeriodEnd","type":"uint256"},{"internalType":"uint256","name":"rewardsPerSecond","type":"uint256"},{"internalType":"address","name":"lpTokenAddress","type":"address"},{"internalType":"uint256","name":"userDepositAmount","type":"uint256"},{"internalType":"uint256","name":"userLpBalance","type":"uint256"},{"internalType":"uint256","name":"userLpApproved","type":"uint256"},{"internalType":"uint256","name":"amountToHarvest","type":"uint256"},{"internalType":"uint256","name":"lpToHarvest","type":"uint256"},{"internalType":"uint256","name":"currentTime","type":"uint256"},{"internalType":"uint256","name":"ricePerEth","type":"uint256"},{"internalType":"uint256","name":"lpPerEth","type":"uint256"}],"internalType":"struct FARM.UserInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lpPerEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"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":"rewardPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPeriodEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPeriodStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardedLpPerDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsPerDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsPerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsUpdatedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rice","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ricePerEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_rice","type":"address"}],"name":"setRiceAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalDeposited","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLpRewards","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":[],"name":"waitingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]