Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add farmer tax to contracts with TaxCollector #36

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
8,146 changes: 8,146 additions & 0 deletions build/contracts/FarmPool.json

Large diffs are not rendered by default.

8,308 changes: 8,308 additions & 0 deletions build/contracts/HAMTaxCollector.json

Large diffs are not rendered by default.

8,215 changes: 8,215 additions & 0 deletions build/contracts/HamToken.json

Large diffs are not rendered by default.

8,322 changes: 8,322 additions & 0 deletions build/contracts/IUniswapV2Router01.json

Large diffs are not rendered by default.

13,444 changes: 13,444 additions & 0 deletions build/contracts/UniswapV2Library.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions clean_build/contracts/FarmPool.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"abi": [{"constant": false, "inputs": [], "name": "withdrawTax", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}], "networks": {}}
1 change: 1 addition & 0 deletions clean_build/contracts/HAMTaxCollector.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"abi": [{"inputs": [{"internalType": "address", "name": "uniFactory_", "type": "address"}, {"internalType": "address", "name": "uniRouter_", "type": "address"}, {"internalType": "address", "name": "hamToken_", "type": "address"}, {"internalType": "address", "name": "beneficiary_", "type": "address"}, {"internalType": "address[]", "name": "farms", "type": "address[]"}], "payable": false, "stateMutability": "nonpayable", "type": "constructor"}, {"anonymous": false, "inputs": [{"indexed": false, "internalType": "uint256", "name": "amountIn", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "amountOut", "type": "uint256"}], "name": "TaxesCollected", "type": "event"}, {"constant": true, "inputs": [], "name": "beneficiary", "outputs": [{"internalType": "address", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "name": "farmsToTax", "outputs": [{"internalType": "address", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "hamToken", "outputs": [{"internalType": "contract HamToken", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "uniFactory", "outputs": [{"internalType": "address", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "uniRouter", "outputs": [{"internalType": "address", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "weth", "outputs": [{"internalType": "address", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "farm", "type": "address"}], "name": "addFarm", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [], "name": "collectTaxes", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}], "networks": {}}
1 change: 1 addition & 0 deletions clean_build/contracts/HamToken.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"abi": [{"constant": false, "inputs": [{"internalType": "address", "name": "to", "type": "address"}, {"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "transfer", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "from", "type": "address"}, {"internalType": "address", "name": "to", "type": "address"}, {"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "transferFrom", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "who", "type": "address"}], "name": "balanceOf", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}], "networks": {}}
1 change: 1 addition & 0 deletions clean_build/contracts/IUniswapV2Router01.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"abi": [{"constant": false, "inputs": [{"internalType": "uint256", "name": "amountIn", "type": "uint256"}, {"internalType": "uint256", "name": "amountOutMin", "type": "uint256"}, {"internalType": "address[]", "name": "path", "type": "address[]"}, {"internalType": "address", "name": "to", "type": "address"}, {"internalType": "uint256", "name": "deadline", "type": "uint256"}], "name": "swapExactTokensForTokens", "outputs": [{"internalType": "uint256[]", "name": "amounts", "type": "uint256[]"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "amountOut", "type": "uint256"}, {"internalType": "uint256", "name": "amountInMax", "type": "uint256"}, {"internalType": "address[]", "name": "path", "type": "address[]"}, {"internalType": "address", "name": "to", "type": "address"}, {"internalType": "uint256", "name": "deadline", "type": "uint256"}], "name": "swapTokensForExactETH", "outputs": [{"internalType": "uint256[]", "name": "amounts", "type": "uint256[]"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "amountIn", "type": "uint256"}, {"internalType": "uint256", "name": "amountOutMin", "type": "uint256"}, {"internalType": "address[]", "name": "path", "type": "address[]"}, {"internalType": "address", "name": "to", "type": "address"}, {"internalType": "uint256", "name": "deadline", "type": "uint256"}], "name": "swapExactTokensForETH", "outputs": [{"internalType": "uint256[]", "name": "amounts", "type": "uint256[]"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "amountA", "type": "uint256"}, {"internalType": "uint256", "name": "reserveA", "type": "uint256"}, {"internalType": "uint256", "name": "reserveB", "type": "uint256"}], "name": "quote", "outputs": [{"internalType": "uint256", "name": "amountB", "type": "uint256"}], "payable": false, "stateMutability": "pure", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "amountIn", "type": "uint256"}, {"internalType": "uint256", "name": "reserveIn", "type": "uint256"}, {"internalType": "uint256", "name": "reserveOut", "type": "uint256"}], "name": "getAmountOut", "outputs": [{"internalType": "uint256", "name": "amountOut", "type": "uint256"}], "payable": false, "stateMutability": "pure", "type": "function"}], "networks": {}}
1 change: 1 addition & 0 deletions clean_build/contracts/UniswapV2Library.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"abi": [], "networks": {}}
54 changes: 37 additions & 17 deletions contracts/distribution/HAMLENDPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -592,8 +592,6 @@ interface HAM {
function hamsScalingFactor() external returns (uint256);
}



contract LPTokenWrapper {
using SafeMath for uint256;
using SafeERC20 for IERC20;
Expand Down Expand Up @@ -633,13 +631,16 @@ contract HAMLENDPool is LPTokenWrapper, IRewardDistributionRecipient {
uint256 public rewardRate = 0;
uint256 public lastUpdateTime;
uint256 public rewardPerTokenStored;
uint256 public tokensFromTax;
address public taxCollector;
mapping(address => uint256) public userRewardPerTokenPaid;
mapping(address => uint256) public rewards;

event RewardAdded(uint256 reward);
event Staked(address indexed user, uint256 amount);
event Withdrawn(address indexed user, uint256 amount);
event RewardPaid(address indexed user, uint256 reward);
event TaxWithdrawn(address indexed beneficiary, uint256 reward);

modifier checkStart() {
require(block.timestamp >= starttime,"not start");
Expand All @@ -656,6 +657,11 @@ contract HAMLENDPool is LPTokenWrapper, IRewardDistributionRecipient {
_;
}

function setTaxCollector(address newCollector) external onlyOwner {
require(newCollector != address(0x0), "!nonzero");
taxCollector = newCollector;
}

function lastTimeRewardApplicable() public view returns (uint256) {
return Math.min(block.timestamp, periodFinish);
}
Expand Down Expand Up @@ -704,34 +710,48 @@ contract HAMLENDPool is LPTokenWrapper, IRewardDistributionRecipient {
uint256 reward = earned(msg.sender);
if (reward > 0) {
rewards[msg.sender] = 0;
uint256 tax = reward.div(100);
tokensFromTax = tokensFromTax.add(tax);
uint256 scalingFactor = HAM(address(ham)).hamsScalingFactor();
uint256 trueReward = reward.mul(scalingFactor).div(10**18);
uint256 trueReward = reward.sub(tax).mul(scalingFactor).div(10**18);
ham.safeTransfer(msg.sender, trueReward);
emit RewardPaid(msg.sender, trueReward);
}
}

function withdrawTax() public checkStart {
require(msg.sender == taxCollector, "!taxCollector");
uint256 tokens = tokensFromTax;
if (tokens > 0) {
tokensFromTax = 0;
uint256 scalingFactor = HAM(address(ham)).hamsScalingFactor();
uint256 collectedTax = tokens.mul(scalingFactor).div(10**18);
ham.safeTransfer(taxCollector, collectedTax);
emit TaxWithdrawn(taxCollector, collectedTax);
}
}

function notifyRewardAmount(uint256 reward)
external
onlyRewardDistribution
updateReward(address(0))
{
if (block.timestamp > starttime) {
if (block.timestamp >= periodFinish) {
rewardRate = reward.div(DURATION);
} else {
uint256 remaining = periodFinish.sub(block.timestamp);
uint256 leftover = remaining.mul(rewardRate);
rewardRate = reward.add(leftover).div(DURATION);
}
lastUpdateTime = block.timestamp;
periodFinish = block.timestamp.add(DURATION);
emit RewardAdded(reward);
if (block.timestamp >= periodFinish) {
rewardRate = reward.div(DURATION);
} else {
uint256 remaining = periodFinish.sub(block.timestamp);
uint256 leftover = remaining.mul(rewardRate);
rewardRate = reward.add(leftover).div(DURATION);
}
lastUpdateTime = block.timestamp;
periodFinish = block.timestamp.add(DURATION);
emit RewardAdded(reward);
} else {
rewardRate = reward.div(DURATION);
lastUpdateTime = starttime;
periodFinish = starttime.add(DURATION);
emit RewardAdded(reward);
rewardRate = reward.div(DURATION);
lastUpdateTime = starttime;
periodFinish = starttime.add(DURATION);
emit RewardAdded(reward);
}
}
}
81 changes: 81 additions & 0 deletions contracts/lib/UniswapV2Library.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
pragma solidity >=0.5.0;

import './IUniswapV2Pair.sol';
import "./SafeMath.sol";

library UniswapV2Library {
using SafeMath for uint;

// returns sorted token addresses, used to handle return values from pairs sorted in this order
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES');
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS');
}

// calculates the CREATE2 address for a pair without making any external calls
function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(uint(keccak256(abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash
))));
}

// fetches and sorts the reserves for a pair
function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {
(address token0,) = sortTokens(tokenA, tokenB);
(uint reserve0, uint reserve1,) = UniswapPair(pairFor(factory, tokenA, tokenB)).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}

// given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) {
require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT');
require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
amountB = amountA.mul(reserveB) / reserveA;
}

// given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
uint amountInWithFee = amountIn.mul(997);
uint numerator = amountInWithFee.mul(reserveOut);
uint denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}

// given an output amount of an asset and pair reserves, returns a required input amount of the other asset
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) {
require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
uint numerator = reserveIn.mul(amountOut).mul(1000);
uint denominator = reserveOut.sub(amountOut).mul(997);
amountIn = (numerator / denominator).add(1);
}

// performs chained getAmountOut calculations on any number of pairs
function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint[](path.length);
amounts[0] = amountIn;
for (uint i; i < path.length - 1; i++) {
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]);
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
}
}

// performs chained getAmountIn calculations on any number of pairs
function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH');
amounts = new uint[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint i = path.length - 1; i > 0; i--) {
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]);
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
}
}
}
37 changes: 18 additions & 19 deletions contracts/lib/UniswapV2OracleLibrary.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,26 @@ library UniswapV2OracleLibrary {
blockTimestamp = currentBlockTimestamp();
(uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = UniswapPair(pair).getReserves();
if (isToken0) {
priceCumulative = UniswapPair(pair).price0CumulativeLast();
priceCumulative = UniswapPair(pair).price0CumulativeLast();

// if time has elapsed since the last update on the pair, mock the accumulated price values
if (blockTimestampLast != blockTimestamp) {
// subtraction overflow is desired
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
// addition overflow is desired
// counterfactual
priceCumulative += uint(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed;
}
// if time has elapsed since the last update on the pair, mock the accumulated price values
if (blockTimestampLast != blockTimestamp) {
// subtraction overflow is desired
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
// addition overflow is desired
// counterfactual
priceCumulative += uint(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed;
}
} else {
priceCumulative = UniswapPair(pair).price1CumulativeLast();
// if time has elapsed since the last update on the pair, mock the accumulated price values
if (blockTimestampLast != blockTimestamp) {
// subtraction overflow is desired
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
// addition overflow is desired
// counterfactual
priceCumulative += uint(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed;
}
priceCumulative = UniswapPair(pair).price1CumulativeLast();
// if time has elapsed since the last update on the pair, mock the accumulated price values
if (blockTimestampLast != blockTimestamp) {
// subtraction overflow is desired
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
// addition overflow is desired
// counterfactual
priceCumulative += uint(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed;
}
}

}
}
Loading