编译器
0.8.17+commit.8df45f5f
文件 1 的 22:AccessControl.sol
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 22:Calendar.sol
pragma solidity ^0.8.0;
library Calendar {
function periods(
uint64 start,
uint64 end,
uint32 duration
) internal pure returns (uint64 count) {
unchecked {
if (start > end) (start, end) = (end, start);
count = (end - start) / duration;
if (start % duration > end % duration) count += 1;
}
}
}
文件 3 的 22:CommonInterest.sol
pragma solidity ^0.8.4;
abstract contract CommonInterest {
constructor(uint64 interestRate, uint32 accrualPeriod) {
_interestRate = interestRate;
_accrualPeriod = accrualPeriod;
}
error WithdrawalOverDebt();
uint64 internal immutable _interestRate;
uint32 internal immutable _accrualPeriod;
function _deposit(
address depositor,
uint256 amount,
uint64 at
) internal virtual;
function _withdrawal(
address depositor,
uint256 amount,
uint64 at
) internal virtual;
function _withdrawal(address depositor) internal virtual;
function _debt(
address depositor,
uint64 at
) internal view virtual returns (uint256);
function _totalDebt(uint64 at) internal view virtual returns (uint256);
}
文件 4 的 22:CompoundInterest.sol
pragma solidity ^0.8.4;
import {CommonInterest} from "./CommonInterest.sol";
import {Math} from "../lib/Math.sol";
import {Calendar} from "../lib/Calendar.sol";
abstract contract CompoundInterest is CommonInterest {
constructor(uint64 anchor) {
_compoundAnchor = anchor;
}
uint64 private immutable _compoundAnchor;
mapping(address => uint256) private _compoundDeposit;
uint256 private _totalCompoundDeposit;
function _deposit(
address depositor,
uint256 amount,
uint64 at
) internal virtual override(CommonInterest) {
uint256 effect = _converge(
amount,
_interestRate,
at,
_compoundAnchor,
_accrualPeriod
);
_totalCompoundDeposit += effect;
_compoundDeposit[depositor] += effect;
}
function _withdrawal(
address recipient,
uint256 amount,
uint64 at
) internal virtual override(CommonInterest) {
uint256 debt = _debt(recipient, at);
if (amount > debt) {
revert WithdrawalOverDebt();
} else if (amount == debt) {
_withdrawal(recipient);
} else {
uint256 diff = _converge(
amount,
_interestRate,
at,
_compoundAnchor,
_accrualPeriod
);
uint256 deposit = _compoundDeposit[recipient];
if (diff > deposit) diff = deposit;
_compoundDeposit[recipient] -= diff;
_totalCompoundDeposit -= diff;
}
}
function _withdrawal(address recipient) internal virtual override {
uint256 deposit = _compoundDeposit[recipient];
if (deposit != 0) {
_totalCompoundDeposit -= deposit;
_compoundDeposit[recipient] = 0;
}
}
function _debt(
address recipient,
uint64 at
) internal view virtual override returns (uint256) {
return
_converge(
_compoundDeposit[recipient],
_interestRate,
_compoundAnchor,
at,
_accrualPeriod
);
}
function _totalDebt(
uint64 at
) internal view virtual override returns (uint256) {
return
_converge(
_totalCompoundDeposit,
_interestRate,
_compoundAnchor,
at,
_accrualPeriod
);
}
function _converge(
uint256 sum,
uint256 interest,
uint64 from,
uint64 to,
uint32 period
) private pure returns (uint256) {
uint64 periods = Calendar.periods(from, to, period);
if (periods == 0) return sum;
uint256 lever = Math.powerX33(1e33 + interest * 1e15, periods) / 1e15;
uint256 converged = to < from ? (sum * 1e36) / lever : sum * lever;
return Math.fromX18(converged);
}
}
文件 5 的 22: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;
}
}
文件 6 的 22:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 7 的 22:FlexibleInterest.sol
pragma solidity ^0.8.4;
import {CommonInterest} from "./CommonInterest.sol";
import {SimpleInterest} from "./SimpleInterest.sol";
import {CompoundInterest} from "./CompoundInterest.sol";
abstract contract FlexibleInterest is SimpleInterest, CompoundInterest {
constructor(uint256 compoundThreshold) {
_compoundThreshold = compoundThreshold;
}
uint256 internal immutable _compoundThreshold;
mapping(address => uint256) private _impact;
uint256 private _accumulatedImpact;
function _deposit(
address depositor,
uint256 amount,
uint64 at
) internal override(SimpleInterest, CompoundInterest) {
uint256 impact = _impact[depositor];
_impact[depositor] += amount;
_accumulatedImpact += amount;
if (impact >= _compoundThreshold) {
CompoundInterest._deposit(depositor, amount, at);
} else {
if (impact + amount >= _compoundThreshold) {
uint256 debt = SimpleInterest._debt(depositor, at);
if (debt != 0) SimpleInterest._withdrawal(depositor);
CompoundInterest._deposit(depositor, debt + amount, at);
} else {
SimpleInterest._deposit(depositor, amount, at);
}
}
}
function _withdrawal(
address depositor,
uint256 amount,
uint64 at
) internal override(SimpleInterest, CompoundInterest) {
uint256 impact = _impact[depositor];
uint256 decrease = (amount < impact) ? amount : impact;
_impact[depositor] -= decrease;
_accumulatedImpact -= decrease;
if (impact >= _compoundThreshold) {
if (impact - decrease > _compoundThreshold) {
CompoundInterest._withdrawal(depositor, amount, at);
} else {
uint256 debt = CompoundInterest._debt(depositor, at);
if (debt != 0) CompoundInterest._withdrawal(depositor);
if (amount != debt)
SimpleInterest._deposit(depositor, debt - amount, at);
}
} else {
SimpleInterest._withdrawal(depositor, amount, at);
}
}
function _withdrawal(
address depositor
) internal override(SimpleInterest, CompoundInterest) {
uint256 impact = _impact[depositor];
if (impact >= _compoundThreshold)
CompoundInterest._withdrawal(depositor);
else SimpleInterest._withdrawal(depositor);
_accumulatedImpact -= impact;
_impact[depositor] = 0;
}
function _debt(
address depositor,
uint64 at
)
internal
view
override(SimpleInterest, CompoundInterest)
returns (uint256)
{
if (_impact[depositor] >= _compoundThreshold)
return CompoundInterest._debt(depositor, at);
else return SimpleInterest._debt(depositor, at);
}
function _totalDebt(
uint64 at
)
internal
view
override(SimpleInterest, CompoundInterest)
returns (uint256)
{
return CompoundInterest._totalDebt(at) + SimpleInterest._totalDebt(at);
}
function _totalImpact() internal view returns (uint256) {
return _accumulatedImpact;
}
function _impactOf(address investor) internal view returns (uint256) {
return _impact[investor];
}
}
文件 8 的 22:IAccessControl.sol
pragma solidity ^0.8.0;
interface IAccessControl {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 9 的 22:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 10 的 22: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);
}
文件 11 的 22:IStakingCore.sol
pragma solidity ^0.8.4;
interface IStakingCore {
error TokenTransferFailed();
error DepositIsTooEarly();
error DepositIsTooLate();
error DepositRankIsUntrusted();
error DepositRankIsTooLow();
error DepositDeadlineIsReached();
error WithdrawalDelayIsUnwanted();
error WithdrawalIsOffensive();
error NoTokensReadyForClaim();
error RewardIsTooEarly();
error RefundIsTooEarly();
event Deposit(address from, uint256 amount);
event Withdrawal(address to, uint256 amount, uint256 fee);
event DelayedWithdrawal(
address to, uint256 amount, uint256 fee, uint64 until
);
event Claim(address to, uint256 amount);
function version() external pure returns (string memory);
function deposit(
uint256 amount,
uint8 rank,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function withdraw(uint256 amount, bool delayed) external;
function claim(address depositor) external;
function reward(address depositor) external;
function refund(uint256 amount) external;
}
文件 12 的 22:IStakingInfo.sol
pragma solidity ^0.8.4;
interface IStakingInfo {
struct StakingInfo {
string name;
string author;
string website;
address token;
uint64 interestRate;
uint32 accrualPeriod;
uint32 delayedWithdrawalDuration;
uint256 compoundAccrualThreshold;
uint64 delayedWithdrawalFee;
uint64 prematureWithdrawalFee;
uint8 minimalRank;
uint64 startsAt;
uint64 endsAt;
}
event StakingInfoChanged();
function info() external view returns (StakingInfo memory);
}
文件 13 的 22:IStakingPausable.sol
pragma solidity ^0.8.4;
interface IStakingPausable {
error StakingIsPaused();
function pause() external;
function resume() external;
}
文件 14 的 22:IStakingPredictable.sol
pragma solidity ^0.8.4;
interface IStakingPredictable {
struct StakingSummary {
uint256 totalImpact;
uint256 totalDebt;
uint256 totalDelayed;
uint256 balance;
}
function summary() external view returns (StakingSummary memory);
function totalDebt(uint64 at) external view returns (uint256);
}
文件 15 的 22:IStakingStatistics.sol
pragma solidity ^0.8.4;
interface IStakingStatistics {
struct StakingStatistics {
uint256 impact;
uint256 debt;
uint256 pendingWithdrawnTokens;
uint256 readyWithdrawnTokens;
}
function statsOf(address) external view returns (StakingStatistics memory);
}
文件 16 的 22:LimeRank.sol
pragma solidity ^0.8.4;
library LimeRank {
function proof(
address subject,
address issuer,
uint256 deadline,
uint8 rank
) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
keccak256(abi.encodePacked(subject, issuer, deadline, rank))
)
);
}
}
文件 17 的 22: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);
}
}
}
文件 18 的 22:SimpleInterest.sol
pragma solidity ^0.8.4;
import {CommonInterest} from "./CommonInterest.sol";
import {Math} from "../lib/Math.sol";
import {Calendar} from "../lib/Calendar.sol";
abstract contract SimpleInterest is CommonInterest {
constructor(uint64 anchor) {
_simpleAnchor = anchor;
}
uint64 private immutable _simpleAnchor;
mapping(address => int256) private _simpleDeposit;
int256 private _totalSimpleDeposit;
mapping(address => uint256) private _simpleGrowth;
uint256 private _totalSimpleGrowth;
function _deposit(
address depositor,
uint256 amount,
uint64 at
) internal virtual override(CommonInterest) {
amount *= 1e18;
uint256 growthIncrease = (amount * _interestRate) / 1e18;
uint256 elapsed = Calendar.periods(_simpleAnchor, at, _accrualPeriod);
int256 depoDiff = int256(amount) - int256(growthIncrease * elapsed);
_simpleDeposit[depositor] += depoDiff;
_simpleGrowth[depositor] += growthIncrease;
_totalSimpleGrowth += growthIncrease;
_totalSimpleDeposit += depoDiff;
}
function _withdrawal(
address depositor,
uint256 amount,
uint64 at
) internal virtual override(CommonInterest) {
uint256 debt = _debt(depositor, at);
if (amount > debt) {
revert WithdrawalOverDebt();
} else if (amount == debt) {
_withdrawal(depositor);
} else {
uint256 growth = _simpleGrowth[depositor];
uint64 periods = Calendar.periods(
_simpleAnchor,
at,
_accrualPeriod
);
uint256 percent = (amount * 1e36) / debt;
if (percent > 1e18) percent = 1e18;
uint256 growthDecrease = (growth * (1e18 - percent)) / 1e18;
int256 depoDecrease = int256(amount * 1e18) -
int256((growth * periods * (1e18 - percent)) / 1e18);
_totalSimpleDeposit -= depoDecrease;
_totalSimpleGrowth -= growthDecrease;
_simpleDeposit[depositor] -= depoDecrease;
_simpleGrowth[depositor] -= growthDecrease;
}
}
function _withdrawal(address depositor) internal virtual override {
int256 deposit = _simpleDeposit[depositor];
if (deposit != 0) {
_totalSimpleDeposit -= deposit;
_simpleDeposit[depositor] = 0;
}
uint256 growth = _simpleGrowth[depositor];
if (growth != 0) {
_totalSimpleGrowth -= growth;
_simpleGrowth[depositor] = 0;
}
}
function _debt(
address depositor,
uint64 at
) internal view virtual override(CommonInterest) returns (uint256) {
int256 deposit = _simpleDeposit[depositor];
uint256 growth = _simpleGrowth[depositor];
uint256 periods = Calendar.periods(_simpleAnchor, at, _accrualPeriod);
int256 debt = int256(deposit) + int256(periods * growth);
if (debt < 0) return 0;
else return Math.fromX18(uint256(debt));
}
function _totalDebt(
uint64 at
) internal view virtual override returns (uint256) {
int256 deposit = _totalSimpleDeposit;
uint256 growth = _totalSimpleGrowth;
uint256 periods = Calendar.periods(_simpleAnchor, at, _accrualPeriod);
int256 debt = int256(deposit) + int256(periods * growth);
if (debt < 0) return 0;
else return Math.fromX18(uint256(debt));
}
}
文件 19 的 22:Staking.sol
pragma solidity ^0.8.4;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {TransferDelayer} from "./abstract/TransferDelayer.sol";
import {FlexibleInterest} from "./abstract/FlexibleInterest.sol";
import {CommonInterest} from "./abstract/CommonInterest.sol";
import {CompoundInterest} from "./abstract/CompoundInterest.sol";
import {SimpleInterest} from "./abstract/SimpleInterest.sol";
import {LimeRank} from "./lib/LimeRank.sol";
import {Math} from "./lib/Math.sol";
import {TimeContext} from "./abstract/TimeContext.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {IStakingCore} from "./IStakingCore.sol";
import {IStakingInfo} from "./IStakingInfo.sol";
import {IStakingPredictable} from "./IStakingPredictable.sol";
import {IStakingStatistics} from "./IStakingStatistics.sol";
import {IStakingPausable} from "./IStakingPausable.sol";
contract Staking is
IStakingCore,
IStakingInfo,
IStakingPredictable,
IStakingStatistics,
IStakingPausable,
FlexibleInterest,
TransferDelayer,
TimeContext,
AccessControl
{
constructor(
StakingInfo memory blueprint
)
FlexibleInterest(blueprint.compoundAccrualThreshold)
SimpleInterest(blueprint.startsAt - blueprint.accrualPeriod * 2)
CompoundInterest((blueprint.startsAt + blueprint.endsAt) / 2)
CommonInterest(blueprint.interestRate, blueprint.accrualPeriod)
{
require(blueprint.startsAt < blueprint.endsAt);
require(blueprint.prematureWithdrawalFee < 1e18);
require(blueprint.delayedWithdrawalFee < 1e18);
_name = blueprint.name;
_author = blueprint.author;
_website = blueprint.website;
_token = IERC20(blueprint.token);
_minimalRank = blueprint.minimalRank;
_delayedWithdrawalDuration = blueprint.delayedWithdrawalDuration;
_startsAt = blueprint.startsAt;
_endsAt = blueprint.endsAt;
_delayedWithdrawalFee = blueprint.delayedWithdrawalFee;
_prematureWithdrawalFee = blueprint.prematureWithdrawalFee;
_isPaused = false;
_grantRole(MANAGER_ROLE, _msgSender());
_grantRole(PARTNER_ROLE, _msgSender());
_setRoleAdmin(MANAGER_ROLE, MANAGER_ROLE);
_setRoleAdmin(ARBITER_ROLE, MANAGER_ROLE);
_setRoleAdmin(PARTNER_ROLE, PARTNER_ROLE);
}
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");
bytes32 public constant PARTNER_ROLE = keccak256("PARTNER_ROLE");
bytes32 public constant ARBITER_ROLE = keccak256("ARBITER_ROLE");
string private _name;
string private _author;
string private _website;
IERC20 private immutable _token;
uint8 private immutable _minimalRank;
uint32 private immutable _delayedWithdrawalDuration;
uint64 private immutable _startsAt;
uint64 private _endsAt;
uint64 private immutable _delayedWithdrawalFee;
uint64 private immutable _prematureWithdrawalFee;
bool private _isPaused;
function version() external pure override returns (string memory) {
return "3";
}
function info() external view override returns (StakingInfo memory) {
return
StakingInfo(
_name,
_author,
_website,
address(_token),
_interestRate,
_accrualPeriod,
_delayedWithdrawalDuration,
_compoundThreshold,
_delayedWithdrawalFee,
_prematureWithdrawalFee,
_minimalRank,
_startsAt,
_endsAt
);
}
function summary() external view override returns (StakingSummary memory) {
return
StakingSummary(
_totalImpact(),
_totalDebt(_accrualNow()),
_totalDelayed(),
_token.balanceOf(address(this))
);
}
function totalDebt(uint64 at) external view override returns (uint256) {
if (at > _endsAt) at = _endsAt;
else if (at < _now()) at = _now();
return _totalDebt(at);
}
function statsOf(
address investor
) external view override returns (StakingStatistics memory) {
(uint256 pending, uint256 ready) = _delayedTokensFor(investor, _now());
return
StakingStatistics(
_impactOf(investor),
_debt(investor, _accrualNow()),
pending,
ready
);
}
function deposit(
uint256 amount,
uint8 rank,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external override {
require(amount > 0);
if (_now() >= deadline) revert DepositDeadlineIsReached();
if (_isPaused) revert StakingIsPaused();
if (_now() < _startsAt) revert DepositIsTooEarly();
if (_now() >= _endsAt) revert DepositIsTooLate();
if (_minimalRank != 0) {
address subject = address(this);
address sender = _msgSender();
bytes32 proof = LimeRank.proof(subject, sender, deadline, rank);
address signer = ecrecover(proof, v, r, s);
if (!this.hasRole(ARBITER_ROLE, signer))
revert DepositRankIsUntrusted();
if (rank < _minimalRank) revert DepositRankIsTooLow();
}
_deposit(_msgSender(), amount, _now());
emit Deposit(_msgSender(), amount);
_safe(_token.transferFrom(_msgSender(), address(this), amount));
}
function withdraw(uint256 amount, bool delayed) external override {
require(amount > 0);
if (_now() < _endsAt && _isPaused) revert StakingIsPaused();
_withdrawal(_msgSender(), amount, _accrualNow());
if (delayed) {
if (_now() >= _endsAt) revert WithdrawalDelayIsUnwanted();
uint256 fee = Math.fromX18(amount * _delayedWithdrawalFee);
uint64 unlockAt = _now() + _delayedWithdrawalDuration;
_delayTransfer(_msgSender(), amount - fee, unlockAt);
emit DelayedWithdrawal(_msgSender(), amount, fee, unlockAt);
} else {
uint256 fee;
if (_now() < _endsAt)
fee = Math.fromX18(amount * _prematureWithdrawalFee);
_safe(_token.transfer(_msgSender(), amount - fee));
emit Withdrawal(_msgSender(), amount, fee);
}
if (!_hasEnoughFunds()) revert WithdrawalIsOffensive();
}
function reward(address to) external override onlyRole(MANAGER_ROLE) {
if (_now() < _endsAt) revert RewardIsTooEarly();
uint256 prize = _debt(to, _accrualNow());
_withdrawal(to);
emit Withdrawal(to, prize, 0);
_safe(_token.transfer(to, prize));
if (!_hasEnoughFunds()) revert WithdrawalIsOffensive();
}
function refund(uint256 amount) external override onlyRole(PARTNER_ROLE) {
if (_now() < _endsAt) revert RefundIsTooEarly();
uint256 tokensToGive = _totalDelayed() + _totalDebt(_accrualNow());
uint256 balance = _token.balanceOf(address(this));
if (balance < tokensToGive) revert WithdrawalIsOffensive();
uint256 freeTokens = balance - tokensToGive;
if (amount == 0) amount = freeTokens;
else if (amount > freeTokens) revert WithdrawalIsOffensive();
_safe(_token.transfer(_msgSender(), amount));
}
function claim(address recipient) external override {
uint256 amount = _finalizeDelayedTransfers(recipient, _now());
if (amount == 0) revert NoTokensReadyForClaim();
emit Claim(recipient, amount);
_safe(_token.transfer(recipient, amount));
}
function pause() external override onlyRole(MANAGER_ROLE) {
require(!_isPaused);
_isPaused = true;
}
function resume() external override onlyRole(MANAGER_ROLE) {
require(_isPaused);
_isPaused = false;
}
function stop() external onlyRole(MANAGER_ROLE) {
require(_now() >= _startsAt);
require(_now() < _endsAt);
_endsAt = _now();
emit StakingInfoChanged();
}
function setRequisites(
string calldata name,
string calldata author,
string calldata website
) external onlyRole(MANAGER_ROLE) {
require(
keccak256(abi.encode(_name, _author, _website)) !=
keccak256(abi.encode(name, author, website))
);
(_name, _author, _website) = (name, author, website);
emit StakingInfoChanged();
}
function _hasEnoughFunds() private view returns (bool) {
return
_token.balanceOf(address(this)) >= _totalImpact() + _totalDelayed();
}
function _safe(bool transfer) private pure {
if (!transfer) revert TokenTransferFailed();
}
function _accrualNow() internal view returns (uint64) {
uint64 time = _now();
return time < _endsAt ? time : _endsAt;
}
receive() external payable {
revert();
}
}
文件 20 的 22:Strings.sol
pragma solidity ^0.8.0;
import "./math/Math.sol";
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
文件 21 的 22:TimeContext.sol
pragma solidity ^0.8.4;
abstract contract TimeContext {
function _now() internal view virtual returns (uint64) {
return uint64(block.timestamp);
}
}
文件 22 的 22:TransferDelayer.sol
pragma solidity ^0.8.4;
abstract contract TransferDelayer {
struct DelayedTransfer {
uint192 amount;
uint64 notBefore;
}
mapping(address => DelayedTransfer[]) private _transfers;
uint256 private _delayedValue = 0;
function _delayTransfer(
address recipient,
uint256 amount,
uint64 notBefore
) internal {
assert(amount < 2 ** 192);
_transfers[recipient].push(DelayedTransfer(uint192(amount), notBefore));
_delayedValue += amount;
}
function _finalizeDelayedTransfers(
address recipient,
uint64 moment
) internal returns (uint256) {
DelayedTransfer[] memory transfers = _transfers[recipient];
uint256 i = 0;
uint256 tokensToSend = 0;
for (; i < transfers.length && moment >= transfers[i].notBefore; i++)
tokensToSend += transfers[i].amount;
if (i == 0) {
return 0;
} else if (i == transfers.length) {
delete _transfers[recipient];
} else {
for (uint256 k = 0; k < i; k++) {
_transfers[recipient][k] = transfers[k + i];
_transfers[recipient].pop();
}
}
_delayedValue -= tokensToSend;
return tokensToSend;
}
function _delayedTokensFor(
address recipient,
uint256 moment
) internal view returns (uint256 pending, uint256 ready) {
DelayedTransfer[] memory transfers = _transfers[recipient];
uint256 i = 0;
for (; i < transfers.length && transfers[i].notBefore < moment; i++)
ready += transfers[i].amount;
for (; i < transfers.length; i++) pending += transfers[i].amount;
}
function _totalDelayed() internal view returns (uint256) {
return _delayedValue;
}
}
{
"compilationTarget": {
"contracts/Staking.sol": "Staking"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"author","type":"string"},{"internalType":"string","name":"website","type":"string"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint64","name":"interestRate","type":"uint64"},{"internalType":"uint32","name":"accrualPeriod","type":"uint32"},{"internalType":"uint32","name":"delayedWithdrawalDuration","type":"uint32"},{"internalType":"uint256","name":"compoundAccrualThreshold","type":"uint256"},{"internalType":"uint64","name":"delayedWithdrawalFee","type":"uint64"},{"internalType":"uint64","name":"prematureWithdrawalFee","type":"uint64"},{"internalType":"uint8","name":"minimalRank","type":"uint8"},{"internalType":"uint64","name":"startsAt","type":"uint64"},{"internalType":"uint64","name":"endsAt","type":"uint64"}],"internalType":"struct IStakingInfo.StakingInfo","name":"blueprint","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DepositDeadlineIsReached","type":"error"},{"inputs":[],"name":"DepositIsTooEarly","type":"error"},{"inputs":[],"name":"DepositIsTooLate","type":"error"},{"inputs":[],"name":"DepositRankIsTooLow","type":"error"},{"inputs":[],"name":"DepositRankIsUntrusted","type":"error"},{"inputs":[],"name":"NoTokensReadyForClaim","type":"error"},{"inputs":[],"name":"RefundIsTooEarly","type":"error"},{"inputs":[],"name":"RewardIsTooEarly","type":"error"},{"inputs":[],"name":"StakingIsPaused","type":"error"},{"inputs":[],"name":"TokenTransferFailed","type":"error"},{"inputs":[],"name":"WithdrawalDelayIsUnwanted","type":"error"},{"inputs":[],"name":"WithdrawalIsOffensive","type":"error"},{"inputs":[],"name":"WithdrawalOverDebt","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"until","type":"uint64"}],"name":"DelayedWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[],"name":"StakingInfoChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[],"name":"ARBITER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PARTNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"rank","type":"uint8"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"info","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"author","type":"string"},{"internalType":"string","name":"website","type":"string"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint64","name":"interestRate","type":"uint64"},{"internalType":"uint32","name":"accrualPeriod","type":"uint32"},{"internalType":"uint32","name":"delayedWithdrawalDuration","type":"uint32"},{"internalType":"uint256","name":"compoundAccrualThreshold","type":"uint256"},{"internalType":"uint64","name":"delayedWithdrawalFee","type":"uint64"},{"internalType":"uint64","name":"prematureWithdrawalFee","type":"uint64"},{"internalType":"uint8","name":"minimalRank","type":"uint8"},{"internalType":"uint64","name":"startsAt","type":"uint64"},{"internalType":"uint64","name":"endsAt","type":"uint64"}],"internalType":"struct IStakingInfo.StakingInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"reward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"author","type":"string"},{"internalType":"string","name":"website","type":"string"}],"name":"setRequisites","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"investor","type":"address"}],"name":"statsOf","outputs":[{"components":[{"internalType":"uint256","name":"impact","type":"uint256"},{"internalType":"uint256","name":"debt","type":"uint256"},{"internalType":"uint256","name":"pendingWithdrawnTokens","type":"uint256"},{"internalType":"uint256","name":"readyWithdrawnTokens","type":"uint256"}],"internalType":"struct IStakingStatistics.StakingStatistics","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"summary","outputs":[{"components":[{"internalType":"uint256","name":"totalImpact","type":"uint256"},{"internalType":"uint256","name":"totalDebt","type":"uint256"},{"internalType":"uint256","name":"totalDelayed","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"}],"internalType":"struct IStakingPredictable.StakingSummary","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"at","type":"uint64"}],"name":"totalDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"delayed","type":"bool"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]