编译器
0.8.17+commit.8df45f5f
文件 1 的 29:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 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 functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 29:AddressArray.sol
pragma solidity ^0.8.0;
pragma abicoder v1;
library AddressArray {
error IndexOutOfBounds();
error PopFromEmptyArray();
error OutputArrayTooSmall();
struct Data {
mapping(uint256 => uint256) _raw;
}
function length(Data storage self) internal view returns (uint256) {
return self._raw[0] >> 160;
}
function at(Data storage self, uint256 i) internal view returns (address) {
return address(uint160(self._raw[i]));
}
function get(Data storage self) internal view returns (address[] memory arr) {
uint256 lengthAndFirst = self._raw[0];
arr = new address[](lengthAndFirst >> 160);
_get(self, arr, lengthAndFirst);
}
function get(Data storage self, address[] memory output) internal view returns (address[] memory) {
return _get(self, output, self._raw[0]);
}
function _get(
Data storage self,
address[] memory output,
uint256 lengthAndFirst
) private view returns (address[] memory) {
uint256 len = lengthAndFirst >> 160;
if (len > output.length) revert OutputArrayTooSmall();
if (len > 0) {
output[0] = address(uint160(lengthAndFirst));
unchecked {
for (uint256 i = 1; i < len; i++) {
output[i] = address(uint160(self._raw[i]));
}
}
}
return output;
}
function push(Data storage self, address account) internal returns (uint256) {
unchecked {
uint256 lengthAndFirst = self._raw[0];
uint256 len = lengthAndFirst >> 160;
if (len == 0) {
self._raw[0] = (1 << 160) + uint160(account);
} else {
self._raw[0] = lengthAndFirst + (1 << 160);
self._raw[len] = uint160(account);
}
return len + 1;
}
}
function pop(Data storage self) internal {
unchecked {
uint256 lengthAndFirst = self._raw[0];
uint256 len = lengthAndFirst >> 160;
if (len == 0) revert PopFromEmptyArray();
self._raw[len - 1] = 0;
if (len > 1) {
self._raw[0] = lengthAndFirst - (1 << 160);
}
}
}
function set(
Data storage self,
uint256 index,
address account
) internal {
uint256 len = length(self);
if (index >= len) revert IndexOutOfBounds();
if (index == 0) {
self._raw[0] = (len << 160) | uint160(account);
} else {
self._raw[index] = uint160(account);
}
}
}
文件 3 的 29:AddressSet.sol
pragma solidity ^0.8.0;
pragma abicoder v1;
import "./AddressArray.sol";
library AddressSet {
using AddressArray for AddressArray.Data;
struct Data {
AddressArray.Data items;
mapping(address => uint256) lookup;
}
function length(Data storage s) internal view returns (uint256) {
return s.items.length();
}
function at(Data storage s, uint256 index) internal view returns (address) {
return s.items.at(index);
}
function contains(Data storage s, address item) internal view returns (bool) {
return s.lookup[item] != 0;
}
function add(Data storage s, address item) internal returns (bool) {
if (s.lookup[item] > 0) {
return false;
}
s.lookup[item] = s.items.push(item);
return true;
}
function remove(Data storage s, address item) internal returns (bool) {
uint256 index = s.lookup[item];
if (index == 0) {
return false;
}
if (index < s.items.length()) {
unchecked {
address lastItem = s.items.at(s.items.length() - 1);
s.items.set(index - 1, lastItem);
s.lookup[lastItem] = index;
}
}
s.items.pop();
delete s.lookup[item];
return true;
}
}
文件 4 的 29: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;
}
}
文件 5 的 29:ERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
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);
}
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
文件 6 的 29:ERC20Pods.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@1inch/solidity-utils/contracts/libraries/AddressSet.sol";
import "./interfaces/IERC20Pods.sol";
import "./interfaces/IPod.sol";
import "./libs/ReentrancyGuard.sol";
abstract contract ERC20Pods is ERC20, IERC20Pods, ReentrancyGuardExt {
using AddressSet for AddressSet.Data;
using AddressArray for AddressArray.Data;
using ReentrancyGuardLib for ReentrancyGuardLib.Data;
error PodAlreadyAdded();
error PodNotFound();
error InvalidPodAddress();
error PodsLimitReachedForAccount();
error InsufficientGas();
error ZeroPodsLimit();
uint256 public immutable podsLimit;
uint256 public immutable podCallGasLimit;
ReentrancyGuardLib.Data private _guard;
mapping(address => AddressSet.Data) private _pods;
constructor(uint256 podsLimit_, uint256 podCallGasLimit_) {
if (podsLimit_ == 0) revert ZeroPodsLimit();
podsLimit = podsLimit_;
podCallGasLimit = podCallGasLimit_;
_guard.init();
}
function hasPod(address account, address pod) public view virtual returns(bool) {
return _pods[account].contains(pod);
}
function podsCount(address account) public view virtual returns(uint256) {
return _pods[account].length();
}
function podAt(address account, uint256 index) public view virtual returns(address) {
return _pods[account].at(index);
}
function pods(address account) public view virtual returns(address[] memory) {
return _pods[account].items.get();
}
function balanceOf(address account) public nonReentrantView(_guard) view override(IERC20, ERC20) virtual returns(uint256) {
return super.balanceOf(account);
}
function podBalanceOf(address pod, address account) public nonReentrantView(_guard) view virtual returns(uint256) {
if (hasPod(account, pod)) {
return super.balanceOf(account);
}
return 0;
}
function addPod(address pod) public virtual {
_addPod(msg.sender, pod);
}
function removePod(address pod) public virtual {
_removePod(msg.sender, pod);
}
function removeAllPods() public virtual {
_removeAllPods(msg.sender);
}
function _addPod(address account, address pod) internal virtual {
if (pod == address(0)) revert InvalidPodAddress();
if (!_pods[account].add(pod)) revert PodAlreadyAdded();
if (_pods[account].length() > podsLimit) revert PodsLimitReachedForAccount();
emit PodAdded(account, pod);
uint256 balance = balanceOf(account);
if (balance > 0) {
_updateBalances(pod, address(0), account, balance);
}
}
function _removePod(address account, address pod) internal virtual {
if (!_pods[account].remove(pod)) revert PodNotFound();
emit PodRemoved(account, pod);
uint256 balance = balanceOf(account);
if (balance > 0) {
_updateBalances(pod, account, address(0), balance);
}
}
function _removeAllPods(address account) internal virtual {
address[] memory items = _pods[account].items.get();
uint256 balance = balanceOf(account);
unchecked {
for (uint256 i = items.length; i > 0; i--) {
_pods[account].remove(items[i - 1]);
emit PodRemoved(account, items[i - 1]);
if (balance > 0) {
_updateBalances(items[i - 1], account, address(0), balance);
}
}
}
}
function _updateBalances(address pod, address from, address to, uint256 amount) private {
bytes4 selector = IPod.updateBalances.selector;
bytes4 exception = InsufficientGas.selector;
uint256 gasLimit = podCallGasLimit;
assembly {
let ptr := mload(0x40)
mstore(ptr, selector)
mstore(add(ptr, 0x04), from)
mstore(add(ptr, 0x24), to)
mstore(add(ptr, 0x44), amount)
if lt(div(mul(gas(), 63), 64), gasLimit) {
mstore(0, exception)
revert(0, 4)
}
pop(call(gasLimit, pod, 0, ptr, 0x64, 0, 0))
}
}
function _afterTokenTransfer(address from, address to, uint256 amount) internal nonReentrant(_guard) override virtual {
super._afterTokenTransfer(from, to, amount);
unchecked {
if (amount > 0 && from != to) {
address[] memory a = _pods[from].items.get();
address[] memory b = _pods[to].items.get();
uint256 aLength = a.length;
uint256 bLength = b.length;
for (uint256 i = 0; i < aLength; i++) {
address pod = a[i];
uint256 j;
for (j = 0; j < bLength; j++) {
if (pod == b[j]) {
_updateBalances(pod, from, to, amount);
b[j] = address(0);
break;
}
}
if (j == bLength) {
_updateBalances(pod, from, address(0), amount);
}
}
for (uint256 j = 0; j < bLength; j++) {
address pod = b[j];
if (pod != address(0)) {
_updateBalances(pod, address(0), to, amount);
}
}
}
}
}
}
文件 7 的 29:ERC20PodsMock.sol
pragma solidity >0.0.0;
import '@1inch/erc20-pods/contracts/mocks/ERC20PodsMock.sol';
文件 8 的 29:FarmAccounting.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/math/Math.sol";
library FarmAccounting {
error ZeroDuration();
error DurationTooLarge();
error AmountTooLarge();
struct Info {
uint40 finished;
uint32 duration;
uint184 reward;
}
uint256 internal constant _MAX_REWARD_AMOUNT = 1e32;
uint256 internal constant _SCALE = 1e18;
function farmedSinceCheckpointScaled(Info memory info, uint256 checkpoint) internal view returns(uint256 amount) {
unchecked {
if (info.duration > 0) {
uint256 elapsed = Math.min(block.timestamp, info.finished) - Math.min(checkpoint, info.finished);
return elapsed * info.reward * _SCALE / info.duration;
}
}
}
function startFarming(Info storage info, uint256 amount, uint256 period) internal returns(uint256) {
if (period == 0) revert ZeroDuration();
if (period > type(uint32).max) revert DurationTooLarge();
if (amount > _MAX_REWARD_AMOUNT) revert AmountTooLarge();
Info memory prev = info;
if (block.timestamp < prev.finished) {
amount += prev.reward - farmedSinceCheckpointScaled(prev, prev.finished - prev.duration) / _SCALE;
}
(info.finished, info.duration, info.reward) = (uint40(block.timestamp + period), uint32(period), uint184(amount));
return amount;
}
}
文件 9 的 29:FarmingLib.sol
pragma solidity ^0.8.0;
import "./accounting/FarmAccounting.sol";
import "./accounting/UserAccounting.sol";
library FarmingLib {
using FarmAccounting for FarmAccounting.Info;
using UserAccounting for UserAccounting.Info;
using FarmingLib for FarmingLib.Info;
struct Data {
FarmAccounting.Info farmInfo;
UserAccounting.Info userInfo;
}
struct Info {
function() internal view returns(uint256) getTotalSupply;
bytes32 dataSlot;
}
function makeInfo(function() internal view returns(uint256) getTotalSupply, Data storage data) internal pure returns(Info memory info) {
info.getTotalSupply = getTotalSupply;
bytes32 dataSlot;
assembly {
dataSlot := data.slot
}
info.dataSlot = dataSlot;
}
function getData(Info memory self) internal pure returns(Data storage data) {
bytes32 dataSlot = self.dataSlot;
assembly {
data.slot := dataSlot
}
}
function startFarming(Info memory self, uint256 amount, uint256 period) internal returns(uint256 reward) {
Data storage data = self.getData();
data.userInfo.updateFarmedPerToken(_farmedPerToken(self));
reward = data.farmInfo.startFarming(amount, period);
}
function farmed(Info memory self, address account, uint256 balance) internal view returns(uint256) {
return self.getData().userInfo.farmed(account, balance, _farmedPerToken(self));
}
function claim(Info memory self, address account, uint256 balance) internal returns(uint256 amount) {
Data storage data = self.getData();
uint256 fpt = _farmedPerToken(self);
amount = data.userInfo.farmed(account, balance, fpt);
if (amount > 0) {
data.userInfo.eraseFarmed(account, balance, fpt);
}
}
function updateBalances(Info memory self, address from, address to, uint256 amount) internal {
self.getData().userInfo.updateBalances(from, to, amount, _farmedPerToken(self));
}
function _farmedPerToken(Info memory self) private view returns (uint256) {
return self.getData().userInfo.farmedPerToken(_infoToContext(self), _lazyGetSupply, _lazyGetFarmed);
}
function _lazyGetSupply(bytes32 context) private view returns(uint256) {
Info memory self = _contextToInfo(context);
return self.getTotalSupply();
}
function _lazyGetFarmed(bytes32 context, uint256 checkpoint) private view returns(uint256) {
Info memory self = _contextToInfo(context);
return self.getData().farmInfo.farmedSinceCheckpointScaled(checkpoint);
}
function _contextToInfo(bytes32 context) private pure returns(Info memory self) {
assembly {
self := context
}
}
function _infoToContext(Info memory self) private pure returns(bytes32 context) {
assembly {
context := self
}
}
}
文件 10 的 29:FarmingPod.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import "@1inch/erc20-pods/contracts/Pod.sol";
import "@1inch/erc20-pods/contracts/interfaces/IERC20Pods.sol";
import "./interfaces/IFarmingPod.sol";
import "./FarmingLib.sol";
contract FarmingPod is Pod, IFarmingPod, Ownable {
using SafeERC20 for IERC20;
using FarmingLib for FarmingLib.Info;
using Address for address payable;
error ZeroFarmableTokenAddress();
error ZeroRewardsTokenAddress();
error SameDistributor();
IERC20 public immutable rewardsToken;
address private _distributor;
uint256 private _totalSupply;
FarmingLib.Data private _farm;
modifier onlyDistributor {
if (msg.sender != _distributor) revert AccessDenied();
_;
}
constructor(IERC20Pods farmableToken_, IERC20 rewardsToken_)
Pod(farmableToken_)
{
if (address(farmableToken_) == address(0)) revert ZeroFarmableTokenAddress();
if (address(rewardsToken_) == address(0)) revert ZeroRewardsTokenAddress();
rewardsToken = rewardsToken_;
emit FarmCreated(address(farmableToken_), address(rewardsToken_));
}
function farmInfo() public view returns(FarmAccounting.Info memory) {
return _farm.farmInfo;
}
function totalSupply() public view returns(uint256) {
return _totalSupply;
}
function distributor() public view returns(address) {
return _distributor;
}
function setDistributor(address distributor_) public virtual onlyOwner {
address oldDistributor = _distributor;
if (distributor_ == oldDistributor) revert SameDistributor();
emit DistributorChanged(oldDistributor, distributor_);
_distributor = distributor_;
}
function startFarming(uint256 amount, uint256 period) public virtual onlyDistributor {
uint256 reward = _makeInfo().startFarming(amount, period);
emit RewardAdded(reward, period);
rewardsToken.safeTransferFrom(msg.sender, address(this), amount);
}
function farmed(address account) public view virtual returns(uint256) {
uint256 balance = IERC20Pods(token).podBalanceOf(address(this), account);
return _makeInfo().farmed(account, balance);
}
function claim() public virtual {
uint256 podBalance = IERC20Pods(token).podBalanceOf(address(this), msg.sender);
uint256 amount = _makeInfo().claim(msg.sender, podBalance);
if (amount > 0) {
_transferReward(rewardsToken, msg.sender, amount);
}
}
function _transferReward(IERC20 reward, address to, uint256 amount) internal virtual {
reward.safeTransfer(to, amount);
}
function _updateBalances(address from, address to, uint256 amount) internal virtual override {
_makeInfo().updateBalances(from, to, amount);
if (from == address(0)) {
_totalSupply += amount;
}
if (to == address(0)) {
_totalSupply -= amount;
}
}
function rescueFunds(IERC20 token, uint256 amount) public virtual onlyDistributor {
if(token == IERC20(address(0))) {
payable(_distributor).sendValue(amount);
} else {
token.safeTransfer(_distributor, amount);
}
}
function _makeInfo() private view returns(FarmingLib.Info memory) {
return FarmingLib.makeInfo(totalSupply, _farm);
}
}
文件 11 的 29:FarmingPool.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import "./interfaces/IFarmingPool.sol";
import "./FarmingLib.sol";
contract FarmingPool is IFarmingPool, Ownable, ERC20 {
using SafeERC20 for IERC20;
using Address for address payable;
using FarmingLib for FarmingLib.Info;
error ZeroStakingTokenAddress();
error ZeroRewardsTokenAddress();
error SameDistributor();
error AccessDenied();
error NotEnoughBalance();
error MaxBalanceExceeded();
uint256 internal constant _MAX_BALANCE = 1e32;
IERC20 public immutable stakingToken;
IERC20 public immutable rewardsToken;
address private _distributor;
FarmingLib.Data private _farm;
modifier onlyDistributor {
if (msg.sender != _distributor) revert AccessDenied();
_;
}
constructor(IERC20Metadata stakingToken_, IERC20 rewardsToken_)
ERC20(
string(abi.encodePacked("Farming of ", stakingToken_.name())),
string(abi.encodePacked("farm", stakingToken_.symbol()))
)
{
if (address(stakingToken_) == address(0)) revert ZeroStakingTokenAddress();
if (address(rewardsToken_) == address(0)) revert ZeroRewardsTokenAddress();
stakingToken = stakingToken_;
rewardsToken = rewardsToken_;
}
function decimals() public view virtual override returns (uint8) {
return IERC20Metadata(address(stakingToken)).decimals();
}
function farmInfo() public view returns(FarmAccounting.Info memory) {
return _farm.farmInfo;
}
function distributor() public view virtual returns (address) {
return _distributor;
}
function setDistributor(address distributor_) public virtual onlyOwner {
address oldDistributor = _distributor;
if (distributor_ == oldDistributor) revert SameDistributor();
emit DistributorChanged(oldDistributor, distributor_);
_distributor = distributor_;
}
function startFarming(uint256 amount, uint256 period) public virtual onlyDistributor {
uint256 reward = _makeInfo().startFarming(amount, period);
emit RewardAdded(reward, period);
rewardsToken.safeTransferFrom(msg.sender, address(this), amount);
}
function farmed(address account) public view virtual returns (uint256) {
return _makeInfo().farmed(account, balanceOf(account));
}
function deposit(uint256 amount) public virtual {
_mint(msg.sender, amount);
if (balanceOf(msg.sender) > _MAX_BALANCE) revert MaxBalanceExceeded();
stakingToken.safeTransferFrom(msg.sender, address(this), amount);
}
function withdraw(uint256 amount) public virtual {
_burn(msg.sender, amount);
stakingToken.safeTransfer(msg.sender, amount);
}
function claim() public virtual {
uint256 amount = _makeInfo().claim(msg.sender, balanceOf(msg.sender));
if (amount > 0) {
_transferReward(rewardsToken, msg.sender, amount);
}
}
function _transferReward(IERC20 reward, address to, uint256 amount) internal virtual {
reward.safeTransfer(to, amount);
}
function exit() public virtual {
withdraw(balanceOf(msg.sender));
claim();
}
function rescueFunds(IERC20 token, uint256 amount) public virtual onlyDistributor {
if (token == IERC20(address(0))) {
payable(_distributor).sendValue(amount);
} else {
token.safeTransfer(_distributor, amount);
if (token == stakingToken) {
if (stakingToken.balanceOf(address(this)) < totalSupply()) revert NotEnoughBalance();
}
}
}
function _makeInfo() private view returns(FarmingLib.Info memory) {
return FarmingLib.makeInfo(totalSupply, _farm);
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
super._beforeTokenTransfer(from, to, amount);
if (amount > 0 && from != to) {
_makeInfo().updateBalances(from, to, amount);
}
}
}
文件 12 的 29:IDaiLikePermit.sol
pragma solidity ^0.8.0;
pragma abicoder v1;
interface IDaiLikePermit {
function permit(
address holder,
address spender,
uint256 nonce,
uint256 expiry,
bool allowed,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
文件 13 的 29: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);
}
文件 14 的 29:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 15 的 29:IERC20Pods.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IERC20Pods is IERC20 {
event PodAdded(address account, address pod);
event PodRemoved(address account, address pod);
function hasPod(address account, address pod) external view returns(bool);
function podsCount(address account) external view returns(uint256);
function podAt(address account, uint256 index) external view returns(address);
function pods(address account) external view returns(address[] memory);
function podBalanceOf(address pod, address account) external view returns(uint256);
function addPod(address pod) external;
function removePod(address pod) external;
function removeAllPods() external;
}
文件 16 的 29:IFarmingPod.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@1inch/erc20-pods/contracts/interfaces/IPod.sol";
import "../accounting/FarmAccounting.sol";
interface IFarmingPod is IPod {
event FarmCreated(address token, address reward);
event DistributorChanged(address oldDistributor, address newDistributor);
event RewardAdded(uint256 reward, uint256 duration);
function totalSupply() external view returns(uint256);
function distributor() external view returns(address);
function farmInfo() external view returns(FarmAccounting.Info memory);
function farmed(address account) external view returns(uint256);
function claim() external;
function setDistributor(address distributor_) external;
function startFarming(uint256 amount, uint256 period) external;
function rescueFunds(IERC20 token, uint256 amount) external;
}
文件 17 的 29:IFarmingPool.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../accounting/FarmAccounting.sol";
interface IFarmingPool is IERC20 {
event DistributorChanged(address oldDistributor, address newDistributor);
event RewardAdded(uint256 reward, uint256 duration);
function distributor() external view returns(address);
function farmInfo() external view returns(FarmAccounting.Info memory);
function farmed(address account) external view returns(uint256);
function deposit(uint256 amount) external;
function withdraw(uint256 amount) external;
function claim() external;
function exit() external;
function setDistributor(address distributor_) external;
function startFarming(uint256 amount, uint256 period) external;
function rescueFunds(IERC20 token, uint256 amount) external;
}
文件 18 的 29:IMultiFarmingPod.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@1inch/erc20-pods/contracts/interfaces/IPod.sol";
import "../accounting/FarmAccounting.sol";
interface IMultiFarmingPod is IPod {
event FarmCreated(address token, address reward);
event DistributorChanged(address oldDistributor, address newDistributor);
event RewardAdded(address token, uint256 reward, uint256 duration);
function totalSupply() external view returns(uint256);
function distributor() external view returns(address);
function farmInfo(IERC20 rewardsToken) external view returns(FarmAccounting.Info memory);
function farmed(IERC20 rewardsToken, address account) external view returns(uint256);
function claim(IERC20 rewardsToken) external;
function claim() external;
function setDistributor(address distributor_) external;
function startFarming(IERC20 rewardsToken, uint256 amount, uint256 period) external;
function rescueFunds(IERC20 token, uint256 amount) external;
}
文件 19 的 29:IPod.sol
pragma solidity ^0.8.0;
interface IPod {
function updateBalances(address from, address to, uint256 amount) external;
}
文件 20 的 29:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
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 & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1);
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
文件 21 的 29:MultiFarmingPod.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@1inch/erc20-pods/contracts/Pod.sol";
import "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import "@1inch/solidity-utils/contracts/libraries/AddressSet.sol";
import "@1inch/erc20-pods/contracts/interfaces/IERC20Pods.sol";
import "./interfaces/IMultiFarmingPod.sol";
import "./FarmingLib.sol";
contract MultiFarmingPod is Pod, IMultiFarmingPod, Ownable {
using SafeERC20 for IERC20;
using FarmingLib for FarmingLib.Info;
using Address for address payable;
using AddressSet for AddressSet.Data;
using AddressArray for AddressArray.Data;
error ZeroFarmableTokenAddress();
error ZeroRewardsTokenAddress();
error SameDistributor();
error RewardsTokenAlreadyAdded();
error RewardsTokensLimitTooHigh(uint256);
error RewardsTokensLimitReached();
error RewardsTokenNotFound();
uint256 public immutable rewardsTokensLimit;
address private _distributor;
uint256 private _totalSupply;
mapping(IERC20 => FarmingLib.Data) private _farms;
AddressSet.Data private _rewardsTokens;
modifier onlyDistributor {
if (msg.sender != _distributor) revert AccessDenied();
_;
}
constructor(IERC20Pods farmableToken_, uint256 rewardsTokensLimit_) Pod(farmableToken_) {
if (rewardsTokensLimit_ > 5) revert RewardsTokensLimitTooHigh(rewardsTokensLimit_);
if (address(farmableToken_) == address(0)) revert ZeroFarmableTokenAddress();
rewardsTokensLimit = rewardsTokensLimit_;
}
function rewardsTokens() external view returns(address[] memory) {
return _rewardsTokens.items.get();
}
function farmInfo(IERC20 rewardsToken) public view returns(FarmAccounting.Info memory) {
return _farms[rewardsToken].farmInfo;
}
function totalSupply() public view returns(uint256) {
return _totalSupply;
}
function distributor() public view returns(address) {
return _distributor;
}
function setDistributor(address distributor_) public virtual onlyOwner {
address oldDistributor = _distributor;
if (distributor_ == oldDistributor) revert SameDistributor();
emit DistributorChanged(oldDistributor, distributor_);
_distributor = distributor_;
}
function addRewardsToken(address rewardsToken) public virtual onlyOwner {
if (_rewardsTokens.length() == rewardsTokensLimit) revert RewardsTokensLimitReached();
if (!_rewardsTokens.add(rewardsToken)) revert RewardsTokenAlreadyAdded();
emit FarmCreated(address(token), rewardsToken);
}
function startFarming(IERC20 rewardsToken, uint256 amount, uint256 period) public virtual onlyDistributor {
if (!_rewardsTokens.contains(address(rewardsToken))) revert RewardsTokenNotFound();
uint256 reward = _makeInfo(rewardsToken).startFarming(amount, period);
emit RewardAdded(address(rewardsToken), reward, period);
rewardsToken.safeTransferFrom(msg.sender, address(this), amount);
}
function farmed(IERC20 rewardsToken, address account) public view virtual returns(uint256) {
uint256 balance = IERC20Pods(token).podBalanceOf(address(this), account);
return _makeInfo(rewardsToken).farmed(account, balance);
}
function claim(IERC20 rewardsToken) public virtual {
uint256 podBalance = IERC20Pods(token).podBalanceOf(address(this), msg.sender);
_claim(rewardsToken, msg.sender, podBalance);
}
function claim() public virtual {
uint256 podBalance = IERC20Pods(token).podBalanceOf(address(this), msg.sender);
address[] memory tokens = _rewardsTokens.items.get();
unchecked {
for (uint256 i = 0; i < tokens.length; i++) {
_claim(IERC20(tokens[i]), msg.sender, podBalance);
}
}
}
function _claim(IERC20 rewardsToken, address account, uint256 podBalance) private {
uint256 amount = _makeInfo(rewardsToken).claim(account, podBalance);
if (amount > 0) {
_transferReward(rewardsToken, account, amount);
}
}
function _transferReward(IERC20 reward, address to, uint256 amount) internal virtual {
reward.safeTransfer(to, amount);
}
function _updateBalances(address from, address to, uint256 amount) internal virtual override {
address[] memory tokens = _rewardsTokens.items.get();
unchecked {
for (uint256 i = 0; i < tokens.length; i++) {
_makeInfo(IERC20(tokens[i])).updateBalances(from, to, amount);
}
}
if (from == address(0)) {
_totalSupply += amount;
}
if (to == address(0)) {
_totalSupply -= amount;
}
}
function rescueFunds(IERC20 token, uint256 amount) public virtual onlyDistributor {
if(token == IERC20(address(0))) {
payable(_distributor).sendValue(amount);
} else {
token.safeTransfer(_distributor, amount);
}
}
function _makeInfo(IERC20 rewardsToken) private view returns(FarmingLib.Info memory) {
return FarmingLib.makeInfo(totalSupply, _farms[rewardsToken]);
}
}
文件 22 的 29: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);
}
}
文件 23 的 29:Pod.sol
pragma solidity ^0.8.0;
import "./interfaces/IPod.sol";
import "./interfaces/IERC20Pods.sol";
abstract contract Pod is IPod {
error AccessDenied();
IERC20Pods public immutable token;
modifier onlyToken {
if (msg.sender != address(token)) revert AccessDenied();
_;
}
constructor(IERC20Pods token_) {
token = token_;
}
function updateBalances(address from, address to, uint256 amount) external onlyToken {
_updateBalances(from, to, amount);
}
function _updateBalances(address from, address to, uint256 amount) internal virtual;
}
文件 24 的 29:ReentrancyGuard.sol
pragma solidity ^0.8.0;
library ReentrancyGuardLib {
error ReentrantCall();
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
struct Data {
uint256 _status;
}
function init(Data storage self) internal {
self._status = _NOT_ENTERED;
}
function enter(Data storage self) internal {
if (self._status == _ENTERED) revert ReentrantCall();
self._status = _ENTERED;
}
function exit(Data storage self) internal {
self._status = _NOT_ENTERED;
}
function check(Data storage self) internal view returns (bool) {
return self._status == _ENTERED;
}
}
contract ReentrancyGuardExt {
using ReentrancyGuardLib for ReentrancyGuardLib.Data;
modifier nonReentrant(ReentrancyGuardLib.Data storage self) {
self.enter();
_;
self.exit();
}
modifier nonReentrantView(ReentrancyGuardLib.Data storage self) {
if (self.check()) revert ReentrancyGuardLib.ReentrantCall();
_;
}
}
文件 25 的 29:RevertReasonForwarder.sol
pragma solidity ^0.8.0;
pragma abicoder v1;
library RevertReasonForwarder {
function reRevert() internal pure {
assembly {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
文件 26 的 29:SafeERC20.sol
pragma solidity ^0.8.0;
pragma abicoder v1;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "../interfaces/IDaiLikePermit.sol";
import "../libraries/RevertReasonForwarder.sol";
library SafeERC20 {
error SafeTransferFailed();
error SafeTransferFromFailed();
error ForceApproveFailed();
error SafeIncreaseAllowanceFailed();
error SafeDecreaseAllowanceFailed();
error SafePermitBadLength();
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
bytes4 selector = token.transferFrom.selector;
bool success;
assembly {
let data := mload(0x40)
mstore(data, selector)
mstore(add(data, 0x04), from)
mstore(add(data, 0x24), to)
mstore(add(data, 0x44), amount)
success := call(gas(), token, 0, data, 100, 0x0, 0x20)
if success {
switch returndatasize()
case 0 {
success := gt(extcodesize(token), 0)
}
default {
success := and(gt(returndatasize(), 31), eq(mload(0), 1))
}
}
}
if (!success) revert SafeTransferFromFailed();
}
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
if (!_makeCall(token, token.transfer.selector, to, value)) {
revert SafeTransferFailed();
}
}
function forceApprove(
IERC20 token,
address spender,
uint256 value
) internal {
if (!_makeCall(token, token.approve.selector, spender, value)) {
if (
!_makeCall(token, token.approve.selector, spender, 0) ||
!_makeCall(token, token.approve.selector, spender, value)
) {
revert ForceApproveFailed();
}
}
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 allowance = token.allowance(address(this), spender);
if (value > type(uint256).max - allowance) revert SafeIncreaseAllowanceFailed();
forceApprove(token, spender, allowance + value);
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 allowance = token.allowance(address(this), spender);
if (value > allowance) revert SafeDecreaseAllowanceFailed();
forceApprove(token, spender, allowance - value);
}
function safePermit(IERC20 token, bytes calldata permit) internal {
if (!tryPermit(token, permit)) RevertReasonForwarder.reRevert();
}
function tryPermit(IERC20 token, bytes calldata permit) internal returns(bool) {
if (permit.length == 32 * 7) {
return _makeCalldataCall(token, IERC20Permit.permit.selector, permit);
}
if (permit.length == 32 * 8) {
return _makeCalldataCall(token, IDaiLikePermit.permit.selector, permit);
}
revert SafePermitBadLength();
}
function _makeCall(
IERC20 token,
bytes4 selector,
address to,
uint256 amount
) private returns (bool success) {
assembly {
let data := mload(0x40)
mstore(data, selector)
mstore(add(data, 0x04), to)
mstore(add(data, 0x24), amount)
success := call(gas(), token, 0, data, 0x44, 0x0, 0x20)
if success {
switch returndatasize()
case 0 {
success := gt(extcodesize(token), 0)
}
default {
success := and(gt(returndatasize(), 31), eq(mload(0), 1))
}
}
}
}
function _makeCalldataCall(
IERC20 token,
bytes4 selector,
bytes calldata args
) private returns (bool success) {
assembly {
let len := add(4, args.length)
let data := mload(0x40)
mstore(data, selector)
calldatacopy(add(data, 0x04), args.offset, args.length)
success := call(gas(), token, 0, data, len, 0x0, 0x20)
if success {
switch returndatasize()
case 0 {
success := gt(extcodesize(token), 0)
}
default {
success := and(gt(returndatasize(), 31), eq(mload(0), 1))
}
}
}
}
}
文件 27 的 29:TokenMock.sol
pragma solidity ^0.8.0;
pragma abicoder v1;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract TokenMock is ERC20, Ownable {
constructor(string memory name, string memory symbol) ERC20(name, symbol) {}
function mint(address account, uint256 amount) external onlyOwner {
_mint(account, amount);
}
function burn(address account, uint256 amount) external onlyOwner {
_burn(account, amount);
}
}
文件 28 的 29:UserAccounting.sol
pragma solidity ^0.8.0;
import "./FarmAccounting.sol";
library UserAccounting {
struct Info {
uint40 checkpoint;
uint216 farmedPerTokenStored;
mapping(address => int256) corrections;
}
function farmedPerToken(
Info storage info,
bytes32 context,
function(bytes32) internal view returns(uint256) lazyGetSupply,
function(bytes32, uint256) internal view returns(uint256) lazyGetFarmed
) internal view returns(uint256) {
(uint256 checkpoint, uint256 fpt) = (info.checkpoint, info.farmedPerTokenStored);
if (block.timestamp != checkpoint) {
uint256 supply = lazyGetSupply(context);
if (supply > 0) {
unchecked { fpt += lazyGetFarmed(context, checkpoint) / supply; }
}
}
return fpt;
}
function farmed(Info storage info, address account, uint256 balance, uint256 fpt) internal view returns(uint256) {
return uint256(int256(balance * fpt) - info.corrections[account]) / FarmAccounting._SCALE;
}
function eraseFarmed(Info storage info, address account, uint256 balance, uint256 fpt) internal {
info.corrections[account] = int256(balance * fpt);
}
function updateFarmedPerToken(Info storage info, uint256 fpt) internal {
(info.checkpoint, info.farmedPerTokenStored) = (uint40(block.timestamp), uint216(fpt));
}
function updateBalances(Info storage info, address from, address to, uint256 amount, uint256 fpt) internal {
bool fromZero = (from == address(0));
bool toZero = (to == address(0));
if (amount > 0 && from != to) {
if (fromZero || toZero) {
updateFarmedPerToken(info, fpt);
}
int256 diff = int256(amount * fpt);
if (!fromZero) {
info.corrections[from] -= diff;
}
if (!toZero) {
info.corrections[to] += diff;
}
}
}
}
文件 29 的 29:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
{
"compilationTarget": {
"contracts/MultiFarmingPod.sol": "MultiFarmingPod"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 1000000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IERC20Pods","name":"farmableToken_","type":"address"},{"internalType":"uint256","name":"rewardsTokensLimit_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[],"name":"AmountTooLarge","type":"error"},{"inputs":[],"name":"DurationTooLarge","type":"error"},{"inputs":[],"name":"OutputArrayTooSmall","type":"error"},{"inputs":[],"name":"RewardsTokenAlreadyAdded","type":"error"},{"inputs":[],"name":"RewardsTokenNotFound","type":"error"},{"inputs":[],"name":"RewardsTokensLimitReached","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"RewardsTokensLimitTooHigh","type":"error"},{"inputs":[],"name":"SafeTransferFailed","type":"error"},{"inputs":[],"name":"SafeTransferFromFailed","type":"error"},{"inputs":[],"name":"SameDistributor","type":"error"},{"inputs":[],"name":"ZeroDuration","type":"error"},{"inputs":[],"name":"ZeroFarmableTokenAddress","type":"error"},{"inputs":[],"name":"ZeroRewardsTokenAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldDistributor","type":"address"},{"indexed":false,"internalType":"address","name":"newDistributor","type":"address"}],"name":"DistributorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"reward","type":"address"}],"name":"FarmCreated","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":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"RewardAdded","type":"event"},{"inputs":[{"internalType":"address","name":"rewardsToken","type":"address"}],"name":"addRewardsToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"rewardsToken","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"distributor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"rewardsToken","type":"address"}],"name":"farmInfo","outputs":[{"components":[{"internalType":"uint40","name":"finished","type":"uint40"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint184","name":"reward","type":"uint184"}],"internalType":"struct FarmAccounting.Info","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"rewardsToken","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"farmed","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":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsTokensLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"distributor_","type":"address"}],"name":"setDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"rewardsToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"}],"name":"startFarming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20Pods","name":"","type":"address"}],"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":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"updateBalances","outputs":[],"stateMutability":"nonpayable","type":"function"}]