Skip to content
This repository has been archived by the owner on May 5, 2023. It is now read-only.

Feat/farm #1

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ report/

# Node.js deps
node_modules/

# remappings
remappings.txt
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/ds-token"]
path = lib/ds-token
url = https://github.com/dapphub/ds-token
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# install solc version
# example to install other versions: `make solc 0_8_14`
SOLC_VERSION := 0_8_14
SOLC_VERSION := 0_6_12
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we downgrading? Just to be able to use DSToken?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, only for that

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just use solmate instead?

solc:; nix-env -f https://github.com/dapphub/dapptools/archive/master.tar.gz -iA solc-static-versions.solc_${SOLC_VERSION}

clean:; forge clean
Expand Down
1 change: 1 addition & 0 deletions lib/ds-token
Submodule ds-token added at 16f187
97 changes: 66 additions & 31 deletions src/Farm.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
pragma solidity ^0.8.14;
pragma solidity ^0.6.12;

import {GemAbstract} from "dss-interfaces/ERC/GemAbstract.sol";
import {SafeMath} from "./utils/SafeMath.sol";
import {ReentrancyGuard} from "./utils/ReentrancyGuard.sol";

contract Farm is ReentrancyGuard {
using SafeMath for uint256;

contract Farm {
GemAbstract public immutable rewardGem;
GemAbstract public immutable gem;

Expand Down Expand Up @@ -59,11 +55,6 @@ contract Farm is ReentrancyGuard {
_;
}

modifier onlyRewardsDistribution() {
require(msg.sender == rewardsDistribution, "Farm/not-rewards-distribution");
_;
}

modifier updateReward(address account) {
rewardPerTokenStored = rewardPerToken();
lastUpdateTime = lastTimeRewardApplicable();
Expand All @@ -83,6 +74,10 @@ contract Farm is ReentrancyGuard {
emit Rely(msg.sender);
}

/*//////////////////////////////////
Authorization
//////////////////////////////////*/

/**
* @notice Grants `usr` admin access to this contract.
* @param usr The user address.
Expand All @@ -101,6 +96,10 @@ contract Farm is ReentrancyGuard {
emit Deny(usr);
}

/*//////////////////////////////////
Administration
//////////////////////////////////*/

function setRewardsDuration(uint256 _rewardsDuration) external auth {
require(block.timestamp > periodFinish, "Farm/period-no-finished");
rewardsDuration = _rewardsDuration;
Expand Down Expand Up @@ -133,7 +132,9 @@ contract Farm is ReentrancyGuard {
emit PauseChanged(paused);
}

/* ========== VIEWS ========== */
/*//////////////////////////////////
View
//////////////////////////////////*/

function totalSupply() external view returns (uint256) {
return _totalSupply;
Expand All @@ -152,41 +153,49 @@ contract Farm is ReentrancyGuard {
return rewardPerTokenStored;
}
return
rewardPerTokenStored.add(
lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(_totalSupply)
_add(
rewardPerTokenStored,
_div(_mul(_sub(lastTimeRewardApplicable(), lastUpdateTime), rewardRate * 1e18), _totalSupply)
);
}

function earned(address account) public view returns (uint256) {
return
_balances[account].mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(
_add(
_div(_mul(_balances[account], _sub(rewardPerToken(), userRewardPerTokenPaid[account])), 1e18),
rewards[account]
);
}

function getRewardForDuration() external view returns (uint256) {
return rewardRate.mul(rewardsDuration);
return _mul(rewardRate, rewardsDuration);
}

/* ========== MUTATIVE FUNCTIONS ========== */
/*//////////////////////////////////
Operations
//////////////////////////////////*/

function stake(uint256 amount) external nonReentrant notPaused updateReward(msg.sender) {
function stake(uint256 amount) external notPaused updateReward(msg.sender) {
require(amount > 0, "Farm/invalid-amount");
_totalSupply = _totalSupply.add(amount);
_balances[msg.sender] = _balances[msg.sender].add(amount);

_totalSupply = _add(_totalSupply, amount);
_balances[msg.sender] = _add(_balances[msg.sender], amount);
gem.transferFrom(msg.sender, address(this), amount);

emit Staked(msg.sender, amount);
}

function withdraw(uint256 amount) public nonReentrant updateReward(msg.sender) {
function withdraw(uint256 amount) public updateReward(msg.sender) {
require(amount > 0, "Farm/invalid-amount");
_totalSupply = _totalSupply.sub(amount);
_balances[msg.sender] = _balances[msg.sender].sub(amount);

_totalSupply = _sub(_totalSupply, amount);
_balances[msg.sender] = _sub(_balances[msg.sender], amount);
gem.transfer(msg.sender, amount);

emit Withdrawn(msg.sender, amount);
}

function getReward() public nonReentrant updateReward(msg.sender) {
function getReward() public updateReward(msg.sender) {
uint256 reward = rewards[msg.sender];
if (reward > 0) {
rewards[msg.sender] = 0;
Expand All @@ -202,28 +211,54 @@ contract Farm is ReentrancyGuard {

function recoverERC20(address token, uint256 amt, address to) external auth {
require(token != address(gem), "Farm/gem-not-allowed");

GemAbstract(token).transfer(to, amt);

emit Recovered(token, amt, to);
}

function notifyRewardAmount(uint256 reward) external onlyRewardsDistribution updateReward(address(0)) {
function notifyRewardAmount(uint256 reward) external updateReward(address(0)) {
require(wards[msg.sender] == 1 || msg.sender == rewardsDistribution, "Farm/not-authorized");

if (block.timestamp >= periodFinish) {
rewardRate = reward.div(rewardsDuration);
rewardRate = _div(reward, rewardsDuration);
} else {
uint256 remaining = periodFinish.sub(block.timestamp);
uint256 leftover = remaining.mul(rewardRate);
rewardRate = reward.add(leftover).div(rewardsDuration);
uint256 remaining = _sub(periodFinish, block.timestamp);
uint256 leftover = _mul(remaining, rewardRate);
rewardRate = _div(_add(reward, leftover), rewardsDuration);
}

// Ensure the provided reward amount is not more than the balance in the contract.
// This keeps the reward rate in the right range, preventing overflows due to
// very high values of rewardRate in the earned and rewardsPerToken functions;
// Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.
uint balance = rewardGem.balanceOf(address(this));
require(rewardRate <= balance.div(rewardsDuration), "Farm/invalid-reward");
require(rewardRate <= _div(balance, rewardsDuration), "Farm/invalid-reward");

lastUpdateTime = block.timestamp;
periodFinish = block.timestamp.add(rewardsDuration);
periodFinish = _add(block.timestamp, rewardsDuration);

emit RewardAdded(reward);
}

/*//////////////////////////////////
Math
//////////////////////////////////*/

function _add(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x + y) >= x, "Math/add-overflow");
}

function _sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x - y) <= x, "Math/sub-overflow");
}

function _mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x, "Math/mul-overflow");
}

function _div(uint x, uint y) internal pure returns (uint z) {
require(y > 0, "Math/divide-by-zero");
return x / y;
}
}
Loading