编译器
0.8.17+commit.8df45f5f
文件 1 的 19: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 的 19: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;
}
}
文件 3 的 19: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 {}
}
文件 4 的 19:FarmAccounting.sol
pragma solidity ^0.8.0;
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
library FarmAccounting {
error ZeroDuration();
error DurationTooLarge();
error AmountTooLarge();
struct Info {
uint40 finished;
uint32 duration;
uint184 reward;
uint256 balance;
}
uint256 internal constant _MAX_REWARD_AMOUNT = 1e32;
uint256 internal constant _SCALE = 1e18;
function farmedSinceCheckpointScaled(Info storage info, uint256 checkpoint) internal view returns(uint256 amount) {
unchecked {
(uint40 finished, uint32 duration, uint184 reward) = (info.finished, info.duration, info.reward);
if (duration > 0) {
uint256 elapsed = Math.min(block.timestamp, finished) - Math.min(checkpoint, finished);
return elapsed * reward * _SCALE / 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();
(uint40 finished, uint32 duration, uint184 reward, uint256 balance) = (info.finished, info.duration, info.reward, info.balance);
if (block.timestamp < finished) {
amount += reward - farmedSinceCheckpointScaled(info, finished - duration) / _SCALE;
}
if (amount > _MAX_REWARD_AMOUNT) revert AmountTooLarge();
(info.finished, info.duration, info.reward, info.balance) = (
uint40(block.timestamp + period),
uint32(period),
uint184(amount),
balance + amount
);
return amount;
}
function stopFarming(Info storage info) internal returns(uint256 leftover) {
leftover = info.reward - farmedSinceCheckpointScaled(info, info.finished - info.duration) / _SCALE;
(info.finished, info.duration, info.reward, info.balance) = (
uint40(block.timestamp),
uint32(0),
uint184(0),
info.balance - leftover
);
}
function claim(Info storage info, uint256 amount) internal {
info.balance -= amount;
}
}
文件 5 的 19:FarmingLib.sol
pragma solidity ^0.8.0;
import { FarmAccounting } from "./accounting/FarmAccounting.sol";
import { UserAccounting } from "./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 ("memory-safe") {
dataSlot := data.slot
}
info.dataSlot = dataSlot;
}
function getData(Info memory self) internal pure returns(Data storage data) {
bytes32 dataSlot = self.dataSlot;
assembly ("memory-safe") {
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 stopFarming(Info memory self) internal returns(uint256 leftover) {
Data storage data = self.getData();
data.userInfo.updateFarmedPerToken(_farmedPerToken(self));
leftover = data.farmInfo.stopFarming();
}
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);
data.farmInfo.claim(amount);
}
}
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 ("memory-safe") {
self := context
}
}
function _infoToContext(Info memory self) private pure returns(bytes32 context) {
assembly ("memory-safe") {
context := self
}
}
}
文件 6 的 19:FarmingPool.sol
pragma solidity ^0.8.0;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IERC20, ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { SafeERC20 } from "@1inch/solidity-utils/contracts/libraries/SafeERC20.sol";
import { IFarmingPool } from "./interfaces/IFarmingPool.sol";
import { FarmAccounting, FarmingLib } from "./FarmingLib.sol";
contract FarmingPool is IFarmingPool, Ownable, ERC20 {
using SafeERC20 for IERC20;
using Address for address payable;
using FarmingLib for FarmingLib.Info;
error SameStakingAndRewardsTokens();
error ZeroStakingTokenAddress();
error ZeroRewardsTokenAddress();
error ZeroDistributorAddress();
error SameDistributor();
error AccessDenied();
error InsufficientFunds();
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 (stakingToken_ == rewardsToken_) revert SameStakingAndRewardsTokens();
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 {
if (distributor_ == address(0)) revert ZeroDistributorAddress();
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 RewardUpdated(reward, period);
rewardsToken.safeTransferFrom(msg.sender, address(this), amount);
}
function stopFarming() public virtual onlyDistributor {
uint256 leftover = _makeInfo().stopFarming();
emit RewardUpdated(0, 0);
if (leftover > 0) {
rewardsToken.safeTransfer(msg.sender, leftover);
}
}
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 {
if (token == stakingToken) {
if (stakingToken.balanceOf(address(this)) < totalSupply() + amount) revert InsufficientFunds();
} else if (token == rewardsToken) {
if (rewardsToken.balanceOf(address(this)) < _farm.farmInfo.balance + amount) revert InsufficientFunds();
}
token.safeTransfer(_distributor, amount);
}
}
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);
}
}
}
文件 7 的 19:IDaiLikePermit.sol
pragma solidity ^0.8.0;
interface IDaiLikePermit {
function permit(
address holder,
address spender,
uint256 nonce,
uint256 expiry,
bool allowed,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
文件 8 的 19: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);
}
文件 9 的 19: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);
}
文件 10 的 19: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);
}
文件 11 的 19:IFarmingPool.sol
pragma solidity ^0.8.0;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { FarmAccounting } from "../accounting/FarmAccounting.sol";
interface IFarmingPool is IERC20 {
event DistributorChanged(address oldDistributor, address newDistributor);
event RewardUpdated(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;
}
文件 12 的 19:IPermit2.sol
pragma solidity ^0.8.0;
interface IPermit2 {
struct PermitDetails {
address token;
uint160 amount;
uint48 expiration;
uint48 nonce;
}
struct PermitSingle {
PermitDetails details;
address spender;
uint256 sigDeadline;
}
struct PackedAllowance {
uint160 amount;
uint48 expiration;
uint48 nonce;
}
function transferFrom(address user, address spender, uint160 amount, address token) external;
function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;
function allowance(address user, address token, address spender) external view returns (PackedAllowance memory);
}
文件 13 的 19:IWETH.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint256 amount) external;
}
文件 14 的 19: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, "Math: mulDiv overflow");
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 << 3) < value ? 1 : 0);
}
}
}
文件 15 的 19: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);
}
}
文件 16 的 19:RevertReasonForwarder.sol
pragma solidity ^0.8.0;
library RevertReasonForwarder {
function reRevert() internal pure {
assembly ("memory-safe") {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
文件 17 的 19:SafeERC20.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "../interfaces/IDaiLikePermit.sol";
import "../interfaces/IPermit2.sol";
import "../interfaces/IWETH.sol";
import "../libraries/RevertReasonForwarder.sol";
library SafeERC20 {
error SafeTransferFailed();
error SafeTransferFromFailed();
error ForceApproveFailed();
error SafeIncreaseAllowanceFailed();
error SafeDecreaseAllowanceFailed();
error SafePermitBadLength();
error Permit2TransferAmountTooHigh();
address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
bytes4 private constant _PERMIT_LENGTH_ERROR = 0x68275857;
uint256 private constant _RAW_CALL_GAS_LIMIT = 5000;
function safeBalanceOf(
IERC20 token,
address account
) internal view returns(uint256 tokenBalance) {
bytes4 selector = IERC20.balanceOf.selector;
assembly ("memory-safe") {
mstore(0x00, selector)
mstore(0x04, account)
let success := staticcall(gas(), token, 0x00, 0x24, 0x00, 0x20)
tokenBalance := mload(0)
if or(iszero(success), lt(returndatasize(), 0x20)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
function safeTransferFromUniversal(
IERC20 token,
address from,
address to,
uint256 amount,
bool permit2
) internal {
if (permit2) {
safeTransferFromPermit2(token, from, to, amount);
} else {
safeTransferFrom(token, from, to, amount);
}
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
bytes4 selector = token.transferFrom.selector;
bool success;
assembly ("memory-safe") {
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 safeTransferFromPermit2(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
if (amount > type(uint160).max) revert Permit2TransferAmountTooHigh();
bytes4 selector = IPermit2.transferFrom.selector;
bool success;
assembly ("memory-safe") {
let data := mload(0x40)
mstore(data, selector)
mstore(add(data, 0x04), from)
mstore(add(data, 0x24), to)
mstore(add(data, 0x44), amount)
mstore(add(data, 0x64), token)
success := call(gas(), _PERMIT2, 0, data, 0x84, 0x0, 0x0)
if success {
success := gt(extcodesize(_PERMIT2), 0)
}
}
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, msg.sender, address(this), permit)) RevertReasonForwarder.reRevert();
}
function safePermit(IERC20 token, address owner, address spender, bytes calldata permit) internal {
if (!tryPermit(token, owner, spender, permit)) RevertReasonForwarder.reRevert();
}
function tryPermit(IERC20 token, bytes calldata permit) internal returns(bool success) {
return tryPermit(token, msg.sender, address(this), permit);
}
function tryPermit(IERC20 token, address owner, address spender, bytes calldata permit) internal returns(bool success) {
bytes4 permitSelector = IERC20Permit.permit.selector;
bytes4 daiPermitSelector = IDaiLikePermit.permit.selector;
bytes4 permit2Selector = IPermit2.permit.selector;
assembly ("memory-safe") {
let ptr := mload(0x40)
switch permit.length
case 100 {
mstore(ptr, permitSelector)
mstore(add(ptr, 0x04), owner)
mstore(add(ptr, 0x24), spender)
{
let deadline := shr(224, calldataload(add(permit.offset, 0x20)))
let vs := calldataload(add(permit.offset, 0x44))
calldatacopy(add(ptr, 0x44), permit.offset, 0x20)
mstore(add(ptr, 0x64), sub(deadline, 1))
mstore(add(ptr, 0x84), add(27, shr(255, vs)))
calldatacopy(add(ptr, 0xa4), add(permit.offset, 0x24), 0x20)
mstore(add(ptr, 0xc4), shr(1, shl(1, vs)))
}
success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
}
case 72 {
mstore(ptr, daiPermitSelector)
mstore(add(ptr, 0x04), owner)
mstore(add(ptr, 0x24), spender)
{
let expiry := shr(224, calldataload(add(permit.offset, 0x04)))
let vs := calldataload(add(permit.offset, 0x28))
mstore(add(ptr, 0x44), shr(224, calldataload(permit.offset)))
mstore(add(ptr, 0x64), sub(expiry, 1))
mstore(add(ptr, 0x84), true)
mstore(add(ptr, 0xa4), add(27, shr(255, vs)))
calldatacopy(add(ptr, 0xc4), add(permit.offset, 0x08), 0x20)
mstore(add(ptr, 0xe4), shr(1, shl(1, vs)))
}
success := call(gas(), token, 0, ptr, 0x104, 0, 0)
}
case 224 {
mstore(ptr, permitSelector)
calldatacopy(add(ptr, 0x04), permit.offset, permit.length)
success := call(gas(), token, 0, ptr, 0xe4, 0, 0)
}
case 256 {
mstore(ptr, daiPermitSelector)
calldatacopy(add(ptr, 0x04), permit.offset, permit.length)
success := call(gas(), token, 0, ptr, 0x104, 0, 0)
}
case 96 {
mstore(ptr, permit2Selector)
mstore(add(ptr, 0x04), owner)
mstore(add(ptr, 0x24), token)
calldatacopy(add(ptr, 0x50), permit.offset, 0x14)
mstore(add(ptr, 0x64), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x14))), 1)))
mstore(add(ptr, 0x84), shr(224, calldataload(add(permit.offset, 0x18))))
mstore(add(ptr, 0xa4), spender)
mstore(add(ptr, 0xc4), and(0xffffffffffff, sub(shr(224, calldataload(add(permit.offset, 0x1c))), 1)))
mstore(add(ptr, 0xe4), 0x100)
mstore(add(ptr, 0x104), 0x40)
calldatacopy(add(ptr, 0x124), add(permit.offset, 0x20), 0x20)
calldatacopy(add(ptr, 0x144), add(permit.offset, 0x40), 0x20)
success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0)
}
case 352 {
mstore(ptr, permit2Selector)
calldatacopy(add(ptr, 0x04), permit.offset, permit.length)
success := call(gas(), _PERMIT2, 0, ptr, 0x164, 0, 0)
}
default {
mstore(ptr, _PERMIT_LENGTH_ERROR)
revert(ptr, 4)
}
}
}
function _makeCall(
IERC20 token,
bytes4 selector,
address to,
uint256 amount
) private returns (bool success) {
assembly ("memory-safe") {
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 safeDeposit(IWETH weth, uint256 amount) internal {
if (amount > 0) {
bytes4 selector = IWETH.deposit.selector;
assembly ("memory-safe") {
mstore(0, selector)
if iszero(call(gas(), weth, amount, 0, 4, 0, 0)) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
}
}
function safeWithdraw(IWETH weth, uint256 amount) internal {
bytes4 selector = IWETH.withdraw.selector;
assembly ("memory-safe") {
mstore(0, selector)
mstore(4, amount)
if iszero(call(gas(), weth, 0, 0, 0x24, 0, 0)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
function safeWithdrawTo(IWETH weth, uint256 amount, address to) internal {
safeWithdraw(weth, amount);
if (to != address(this)) {
assembly ("memory-safe") {
if iszero(call(_RAW_CALL_GAS_LIMIT, to, amount, 0, 0, 0, 0)) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
}
}
}
}
文件 18 的 19:UserAccounting.sol
pragma solidity ^0.8.0;
import { FarmAccounting } from "./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;
}
}
}
}
文件 19 的 19:draft-IERC20Permit.sol
pragma solidity ^0.8.0;
import "./IERC20Permit.sol";
{
"compilationTarget": {
"node_modules/@1inch/farming/contracts/FarmingPool.sol": "FarmingPool"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": [
":@1inch/=node_modules/@1inch/",
":@arbitrum/=node_modules/@arbitrum/",
":@chainlink/=node_modules/@chainlink/",
":@eth-optimism/=node_modules/@eth-optimism/",
":@gearbox-protocol/=node_modules/@gearbox-protocol/",
":@openzeppelin/=node_modules/@openzeppelin/",
":@redstone-finance/=node_modules/@redstone-finance/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":eth-gas-reporter/=node_modules/eth-gas-reporter/",
":forge-std/=lib/forge-std/src/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"contract IERC20Metadata","name":"stakingToken_","type":"address"},{"internalType":"contract IERC20","name":"rewardsToken_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[],"name":"AmountTooLarge","type":"error"},{"inputs":[],"name":"DurationTooLarge","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"MaxBalanceExceeded","type":"error"},{"inputs":[],"name":"SafeTransferFailed","type":"error"},{"inputs":[],"name":"SafeTransferFromFailed","type":"error"},{"inputs":[],"name":"SameDistributor","type":"error"},{"inputs":[],"name":"SameStakingAndRewardsTokens","type":"error"},{"inputs":[],"name":"ZeroDistributorAddress","type":"error"},{"inputs":[],"name":"ZeroDuration","type":"error"},{"inputs":[],"name":"ZeroRewardsTokenAddress","type":"error"},{"inputs":[],"name":"ZeroStakingTokenAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"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":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":"uint256","name":"reward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"RewardUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"distributor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"farmInfo","outputs":[{"components":[{"internalType":"uint40","name":"finished","type":"uint40"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint184","name":"reward","type":"uint184"},{"internalType":"uint256","name":"balance","type":"uint256"}],"internalType":"struct FarmAccounting.Info","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"farmed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"rewardsToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"distributor_","type":"address"}],"name":"setDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"}],"name":"startFarming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopFarming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]