编译器
0.6.12+commit.27d51765
文件 1 的 34:AccessControl.sol
pragma solidity >=0.6.0 <0.8.0;
import "../utils/EnumerableSet.sol";
import "../utils/Address.sol";
import "../utils/Context.sol";
abstract contract AccessControl is Context {
using EnumerableSet for EnumerableSet.AddressSet;
using Address for address;
struct RoleData {
EnumerableSet.AddressSet members;
bytes32 adminRole;
}
mapping (bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
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) public view returns (bool) {
return _roles[role].members.contains(account);
}
function getRoleMemberCount(bytes32 role) public view returns (uint256) {
return _roles[role].members.length();
}
function getRoleMember(bytes32 role, uint256 index) public view returns (address) {
return _roles[role].members.at(index);
}
function getRoleAdmin(bytes32 role) public view returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual {
require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual {
require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual {
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 {
emit RoleAdminChanged(role, _roles[role].adminRole, adminRole);
_roles[role].adminRole = adminRole;
}
function _grantRole(bytes32 role, address account) private {
if (_roles[role].members.add(account)) {
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) private {
if (_roles[role].members.remove(account)) {
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 34:Address.sol
pragma solidity >=0.6.2 <0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 3 的 34:Context.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 4 的 34:ContractRegistryClient.sol
pragma solidity 0.6.12;
import "./Owned.sol";
import "./Utils.sol";
import "./interfaces/IContractRegistry.sol";
contract ContractRegistryClient is Owned, Utils {
bytes32 internal constant CONTRACT_REGISTRY = "ContractRegistry";
bytes32 internal constant BANCOR_NETWORK = "BancorNetwork";
bytes32 internal constant CONVERTER_FACTORY = "ConverterFactory";
bytes32 internal constant CONVERSION_PATH_FINDER = "ConversionPathFinder";
bytes32 internal constant CONVERTER_UPGRADER = "BancorConverterUpgrader";
bytes32 internal constant CONVERTER_REGISTRY = "BancorConverterRegistry";
bytes32 internal constant CONVERTER_REGISTRY_DATA = "BancorConverterRegistryData";
bytes32 internal constant BNT_TOKEN = "BNTToken";
bytes32 internal constant BANCOR_X = "BancorX";
bytes32 internal constant BANCOR_X_UPGRADER = "BancorXUpgrader";
bytes32 internal constant LIQUIDITY_PROTECTION = "LiquidityProtection";
bytes32 internal constant NETWORK_SETTINGS = "NetworkSettings";
IContractRegistry private _registry;
IContractRegistry private _prevRegistry;
bool private _onlyOwnerCanUpdateRegistry;
modifier only(bytes32 contractName) {
_only(contractName);
_;
}
function _only(bytes32 contractName) internal view {
require(msg.sender == _addressOf(contractName), "ERR_ACCESS_DENIED");
}
constructor(IContractRegistry initialRegistry) internal validAddress(address(initialRegistry)) {
_registry = IContractRegistry(initialRegistry);
_prevRegistry = IContractRegistry(initialRegistry);
}
function updateRegistry() external {
require(msg.sender == owner() || !_onlyOwnerCanUpdateRegistry, "ERR_ACCESS_DENIED");
IContractRegistry newRegistry = IContractRegistry(_addressOf(CONTRACT_REGISTRY));
require(newRegistry != _registry && address(newRegistry) != address(0), "ERR_INVALID_REGISTRY");
require(newRegistry.addressOf(CONTRACT_REGISTRY) != address(0), "ERR_INVALID_REGISTRY");
_prevRegistry = _registry;
_registry = newRegistry;
}
function restoreRegistry() external ownerOnly {
_registry = _prevRegistry;
}
function restrictRegistryUpdate(bool restrictOwnerOnly) public ownerOnly {
_onlyOwnerCanUpdateRegistry = restrictOwnerOnly;
}
function registry() public view returns (IContractRegistry) {
return _registry;
}
function prevRegistry() external view returns (IContractRegistry) {
return _prevRegistry;
}
function onlyOwnerCanUpdateRegistry() external view returns (bool) {
return _onlyOwnerCanUpdateRegistry;
}
function _addressOf(bytes32 contractName) internal view returns (address) {
return _registry.addressOf(contractName);
}
}
文件 5 的 34:EnumerableSet.sol
pragma solidity >=0.6.0 <0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping (bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
bytes32 lastvalue = set._values[lastIndex];
set._values[toDeleteIndex] = lastvalue;
set._indexes[lastvalue] = toDeleteIndex + 1;
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
require(set._values.length > index, "EnumerableSet: index out of bounds");
return set._values[index];
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
}
文件 6 的 34:ICheckpointStore.sol
pragma solidity 0.6.12;
interface ICheckpointStore {
function addCheckpoint(address target) external;
function addPastCheckpoint(address target, uint256 timestamp) external;
function addPastCheckpoints(address[] calldata targets, uint256[] calldata timestamps) external;
function checkpoint(address target) external view returns (uint256);
}
文件 7 的 34:IClaimable.sol
pragma solidity 0.6.12;
interface IClaimable {
function owner() external view returns (address);
function transferOwnership(address newOwner) external;
function acceptOwnership() external;
}
文件 8 的 34:IContractRegistry.sol
pragma solidity 0.6.12;
interface IContractRegistry {
function addressOf(bytes32 contractName) external view returns (address);
}
文件 9 的 34:IConverterAnchor.sol
pragma solidity 0.6.12;
import "../../utility/interfaces/IOwned.sol";
interface IConverterAnchor is IOwned {
}
文件 10 的 34:IDSToken.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../../converter/interfaces/IConverterAnchor.sol";
import "../../utility/interfaces/IOwned.sol";
interface IDSToken is IConverterAnchor, IERC20 {
function issue(address recipient, uint256 amount) external;
function destroy(address recipient, uint256 amount) external;
}
文件 11 的 34:IERC20.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, 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 sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 12 的 34:ILiquidityProtection.sol
pragma solidity 0.6.12;
import "./ILiquidityProtectionStore.sol";
import "./ILiquidityProtectionStats.sol";
import "./ILiquidityProtectionSettings.sol";
import "./ILiquidityProtectionSystemStore.sol";
import "./ITransferPositionCallback.sol";
import "../../utility/interfaces/ITokenHolder.sol";
import "../../token/interfaces/IReserveToken.sol";
import "../../converter/interfaces/IConverterAnchor.sol";
interface ILiquidityProtection {
function store() external view returns (ILiquidityProtectionStore);
function stats() external view returns (ILiquidityProtectionStats);
function settings() external view returns (ILiquidityProtectionSettings);
function systemStore() external view returns (ILiquidityProtectionSystemStore);
function wallet() external view returns (ITokenHolder);
function addLiquidityFor(
address owner,
IConverterAnchor poolAnchor,
IReserveToken reserveToken,
uint256 amount
) external payable returns (uint256);
function addLiquidity(
IConverterAnchor poolAnchor,
IReserveToken reserveToken,
uint256 amount
) external payable returns (uint256);
function removeLiquidity(uint256 id, uint32 portion) external;
function transferPosition(uint256 id, address newProvider) external returns (uint256);
function transferPositionAndNotify(
uint256 id,
address newProvider,
ITransferPositionCallback callback,
bytes calldata data
) external returns (uint256);
}
文件 13 的 34:ILiquidityProtectionSettings.sol
pragma solidity 0.6.12;
import "../../converter/interfaces/IConverterAnchor.sol";
import "../../token/interfaces/IReserveToken.sol";
import "./ILiquidityProvisionEventsSubscriber.sol";
interface ILiquidityProtectionSettings {
function isPoolWhitelisted(IConverterAnchor poolAnchor) external view returns (bool);
function poolWhitelist() external view returns (address[] memory);
function subscribers() external view returns (address[] memory);
function isPoolSupported(IConverterAnchor poolAnchor) external view returns (bool);
function minNetworkTokenLiquidityForMinting() external view returns (uint256);
function defaultNetworkTokenMintingLimit() external view returns (uint256);
function networkTokenMintingLimits(IConverterAnchor poolAnchor) external view returns (uint256);
function addLiquidityDisabled(IConverterAnchor poolAnchor, IReserveToken reserveToken) external view returns (bool);
function minProtectionDelay() external view returns (uint256);
function maxProtectionDelay() external view returns (uint256);
function minNetworkCompensation() external view returns (uint256);
function lockDuration() external view returns (uint256);
function averageRateMaxDeviation() external view returns (uint32);
}
文件 14 的 34:ILiquidityProtectionStats.sol
pragma solidity 0.6.12;
import "../../converter/interfaces/IConverterAnchor.sol";
import "../../token/interfaces/IDSToken.sol";
import "../../token/interfaces/IReserveToken.sol";
interface ILiquidityProtectionStats {
function increaseTotalAmounts(
address provider,
IDSToken poolToken,
IReserveToken reserveToken,
uint256 poolAmount,
uint256 reserveAmount
) external;
function decreaseTotalAmounts(
address provider,
IDSToken poolToken,
IReserveToken reserveToken,
uint256 poolAmount,
uint256 reserveAmount
) external;
function addProviderPool(address provider, IDSToken poolToken) external returns (bool);
function removeProviderPool(address provider, IDSToken poolToken) external returns (bool);
function totalPoolAmount(IDSToken poolToken) external view returns (uint256);
function totalReserveAmount(IDSToken poolToken, IReserveToken reserveToken) external view returns (uint256);
function totalProviderAmount(
address provider,
IDSToken poolToken,
IReserveToken reserveToken
) external view returns (uint256);
function providerPools(address provider) external view returns (IDSToken[] memory);
}
文件 15 的 34:ILiquidityProtectionStore.sol
pragma solidity 0.6.12;
import "../../converter/interfaces/IConverterAnchor.sol";
import "../../token/interfaces/IDSToken.sol";
import "../../token/interfaces/IReserveToken.sol";
import "../../utility/interfaces/IOwned.sol";
interface ILiquidityProtectionStore is IOwned {
function withdrawTokens(
IReserveToken token,
address recipient,
uint256 amount
) external;
function protectedLiquidity(uint256 id)
external
view
returns (
address,
IDSToken,
IReserveToken,
uint256,
uint256,
uint256,
uint256,
uint256
);
function addProtectedLiquidity(
address provider,
IDSToken poolToken,
IReserveToken reserveToken,
uint256 poolAmount,
uint256 reserveAmount,
uint256 reserveRateN,
uint256 reserveRateD,
uint256 timestamp
) external returns (uint256);
function updateProtectedLiquidityAmounts(
uint256 id,
uint256 poolNewAmount,
uint256 reserveNewAmount
) external;
function removeProtectedLiquidity(uint256 id) external;
function lockedBalance(address provider, uint256 index) external view returns (uint256, uint256);
function lockedBalanceRange(
address provider,
uint256 startIndex,
uint256 endIndex
) external view returns (uint256[] memory, uint256[] memory);
function addLockedBalance(
address provider,
uint256 reserveAmount,
uint256 expirationTime
) external returns (uint256);
function removeLockedBalance(address provider, uint256 index) external;
function systemBalance(IReserveToken poolToken) external view returns (uint256);
function incSystemBalance(IReserveToken poolToken, uint256 poolAmount) external;
function decSystemBalance(IReserveToken poolToken, uint256 poolAmount) external;
}
文件 16 的 34:ILiquidityProtectionSystemStore.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../../converter/interfaces/IConverterAnchor.sol";
interface ILiquidityProtectionSystemStore {
function systemBalance(IERC20 poolToken) external view returns (uint256);
function incSystemBalance(IERC20 poolToken, uint256 poolAmount) external;
function decSystemBalance(IERC20 poolToken, uint256 poolAmount) external;
function networkTokensMinted(IConverterAnchor poolAnchor) external view returns (uint256);
function incNetworkTokensMinted(IConverterAnchor poolAnchor, uint256 amount) external;
function decNetworkTokensMinted(IConverterAnchor poolAnchor, uint256 amount) external;
}
文件 17 的 34:ILiquidityProvisionEventsSubscriber.sol
pragma solidity 0.6.12;
import "../../converter/interfaces/IConverterAnchor.sol";
import "../../token/interfaces/IReserveToken.sol";
interface ILiquidityProvisionEventsSubscriber {
function onAddingLiquidity(
address provider,
IConverterAnchor poolAnchor,
IReserveToken reserveToken,
uint256 poolAmount,
uint256 reserveAmount
) external;
function onRemovingLiquidity(
uint256 id,
address provider,
IConverterAnchor poolAnchor,
IReserveToken reserveToken,
uint256 poolAmount,
uint256 reserveAmount
) external;
}
文件 18 的 34:IMintableToken.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IClaimable.sol";
interface IMintableToken is IERC20, IClaimable {
function issue(address to, uint256 amount) external;
function destroy(address from, uint256 amount) external;
}
文件 19 的 34:IOwned.sol
pragma solidity 0.6.12;
interface IOwned {
function owner() external view returns (address);
function transferOwnership(address newOwner) external;
function acceptOwnership() external;
}
文件 20 的 34:IReserveToken.sol
pragma solidity 0.6.12;
interface IReserveToken {
}
文件 21 的 34:IStakingRewards.sol
pragma solidity 0.6.12;
import "../../liquidity-protection/interfaces/ILiquidityProvisionEventsSubscriber.sol";
import "./IStakingRewardsStore.sol";
interface IStakingRewards is ILiquidityProvisionEventsSubscriber {
event RewardsClaimed(address indexed provider, uint256 amount);
event RewardsStaked(address indexed provider, IDSToken indexed poolToken, uint256 amount, uint256 indexed newId);
function store() external view returns (IStakingRewardsStore);
function pendingRewards(address provider) external view returns (uint256);
function pendingPoolRewards(address provider, IDSToken poolToken) external view returns (uint256);
function pendingReserveRewards(
address provider,
IDSToken poolToken,
IReserveToken reserveToken
) external view returns (uint256);
function rewardsMultiplier(
address provider,
IDSToken poolToken,
IReserveToken reserveToken
) external view returns (uint32);
function totalClaimedRewards(address provider) external view returns (uint256);
function claimRewards() external returns (uint256);
function stakeRewards(uint256 maxAmount, IDSToken poolToken) external returns (uint256, uint256);
function storePoolRewards(address[] calldata providers, IDSToken poolToken) external;
}
文件 22 的 34:IStakingRewardsStore.sol
pragma solidity 0.6.12;
import "../../token/interfaces/IReserveToken.sol";
import "../../token/interfaces/IDSToken.sol";
struct PoolProgram {
uint256 startTime;
uint256 endTime;
uint256 rewardRate;
IReserveToken[2] reserveTokens;
uint32[2] rewardShares;
}
struct PoolRewards {
uint256 lastUpdateTime;
uint256 rewardPerToken;
uint256 totalClaimedRewards;
}
struct ProviderRewards {
uint256 rewardPerToken;
uint256 pendingBaseRewards;
uint256 totalClaimedRewards;
uint256 effectiveStakingTime;
uint256 baseRewardsDebt;
uint32 baseRewardsDebtMultiplier;
}
interface IStakingRewardsStore {
function isPoolParticipating(IDSToken poolToken) external view returns (bool);
function isReserveParticipating(IDSToken poolToken, IReserveToken reserveToken) external view returns (bool);
function addPoolProgram(
IDSToken poolToken,
IReserveToken[2] calldata reserveTokens,
uint32[2] calldata rewardShares,
uint256 endTime,
uint256 rewardRate
) external;
function removePoolProgram(IDSToken poolToken) external;
function setPoolProgramEndTime(IDSToken poolToken, uint256 newEndTime) external;
function poolProgram(IDSToken poolToken)
external
view
returns (
uint256,
uint256,
uint256,
IReserveToken[2] memory,
uint32[2] memory
);
function poolPrograms()
external
view
returns (
IDSToken[] memory,
uint256[] memory,
uint256[] memory,
uint256[] memory,
IReserveToken[2][] memory,
uint32[2][] memory
);
function poolRewards(IDSToken poolToken, IReserveToken reserveToken)
external
view
returns (
uint256,
uint256,
uint256
);
function updatePoolRewardsData(
IDSToken poolToken,
IReserveToken reserveToken,
uint256 lastUpdateTime,
uint256 rewardPerToken,
uint256 totalClaimedRewards
) external;
function providerRewards(
address provider,
IDSToken poolToken,
IReserveToken reserveToken
)
external
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256,
uint32
);
function updateProviderRewardsData(
address provider,
IDSToken poolToken,
IReserveToken reserveToken,
uint256 rewardPerToken,
uint256 pendingBaseRewards,
uint256 totalClaimedRewards,
uint256 effectiveStakingTime,
uint256 baseRewardsDebt,
uint32 baseRewardsDebtMultiplier
) external;
function updateProviderLastClaimTime(address provider) external;
function providerLastClaimTime(address provider) external view returns (uint256);
}
文件 23 的 34:ITokenGovernance.sol
pragma solidity 0.6.12;
import "./IMintableToken.sol";
interface ITokenGovernance {
function token() external view returns (IMintableToken);
function mint(address to, uint256 amount) external;
function burn(uint256 amount) external;
}
文件 24 的 34:ITokenHolder.sol
pragma solidity 0.6.12;
import "../../token/interfaces/IReserveToken.sol";
import "./IOwned.sol";
interface ITokenHolder is IOwned {
receive() external payable;
function withdrawTokens(
IReserveToken reserveToken,
address payable to,
uint256 amount
) external;
function withdrawTokensMultiple(
IReserveToken[] calldata reserveTokens,
address payable to,
uint256[] calldata amounts
) external;
}
文件 25 的 34:ITransferPositionCallback.sol
pragma solidity 0.6.12;
interface ITransferPositionCallback {
function onTransferPosition(
uint256 newId,
address provider,
bytes calldata data
) external;
}
文件 26 的 34:Math.sol
pragma solidity >=0.6.0 <0.8.0;
library Math {
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 / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
文件 27 的 34:Owned.sol
pragma solidity 0.6.12;
import "./interfaces/IOwned.sol";
contract Owned is IOwned {
address private _owner;
address private _newOwner;
event OwnerUpdate(address indexed prevOwner, address indexed newOwner);
constructor() public {
_owner = msg.sender;
}
modifier ownerOnly {
_ownerOnly();
_;
}
function _ownerOnly() private view {
require(msg.sender == _owner, "ERR_ACCESS_DENIED");
}
function transferOwnership(address newOwner) public override ownerOnly {
require(newOwner != _owner, "ERR_SAME_OWNER");
_newOwner = newOwner;
}
function acceptOwnership() public override {
require(msg.sender == _newOwner, "ERR_ACCESS_DENIED");
emit OwnerUpdate(_owner, _newOwner);
_owner = _newOwner;
_newOwner = address(0);
}
function owner() public view override returns (address) {
return _owner;
}
function newOwner() external view returns (address) {
return _newOwner;
}
}
文件 28 的 34:ReserveToken.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "./interfaces/IReserveToken.sol";
import "./SafeERC20Ex.sol";
library ReserveToken {
using SafeERC20 for IERC20;
using SafeERC20Ex for IERC20;
IReserveToken public constant NATIVE_TOKEN_ADDRESS = IReserveToken(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
function isNativeToken(IReserveToken reserveToken) internal pure returns (bool) {
return reserveToken == NATIVE_TOKEN_ADDRESS;
}
function balanceOf(IReserveToken reserveToken, address account) internal view returns (uint256) {
if (isNativeToken(reserveToken)) {
return account.balance;
}
return toIERC20(reserveToken).balanceOf(account);
}
function safeTransfer(
IReserveToken reserveToken,
address to,
uint256 amount
) internal {
if (amount == 0) {
return;
}
if (isNativeToken(reserveToken)) {
payable(to).transfer(amount);
} else {
toIERC20(reserveToken).safeTransfer(to, amount);
}
}
function safeTransferFrom(
IReserveToken reserveToken,
address from,
address to,
uint256 amount
) internal {
if (amount == 0 || isNativeToken(reserveToken)) {
return;
}
toIERC20(reserveToken).safeTransferFrom(from, to, amount);
}
function ensureApprove(
IReserveToken reserveToken,
address spender,
uint256 amount
) internal {
if (isNativeToken(reserveToken)) {
return;
}
toIERC20(reserveToken).ensureApprove(spender, amount);
}
function toIERC20(IReserveToken reserveToken) private pure returns (IERC20) {
return IERC20(address(reserveToken));
}
}
文件 29 的 34:SafeERC20.sol
pragma solidity >=0.6.0 <0.8.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 30 的 34:SafeERC20Ex.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
library SafeERC20Ex {
using SafeERC20 for IERC20;
function ensureApprove(
IERC20 token,
address spender,
uint256 amount
) internal {
if (amount == 0) {
return;
}
uint256 allowance = token.allowance(address(this), spender);
if (allowance >= amount) {
return;
}
if (allowance > 0) {
token.safeApprove(spender, 0);
}
token.safeApprove(spender, amount);
}
}
文件 31 的 34:SafeMath.sol
pragma solidity >=0.6.0 <0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
文件 32 的 34:StakingRewards.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@bancor/token-governance/contracts/ITokenGovernance.sol";
import "../utility/ContractRegistryClient.sol";
import "../utility/Utils.sol";
import "../utility/Time.sol";
import "../utility/interfaces/ICheckpointStore.sol";
import "../token/ReserveToken.sol";
import "../liquidity-protection/interfaces/ILiquidityProtection.sol";
import "./interfaces/IStakingRewards.sol";
contract StakingRewards is IStakingRewards, AccessControl, Time, Utils, ContractRegistryClient {
using SafeMath for uint256;
using ReserveToken for IReserveToken;
using SafeERC20 for IERC20;
using SafeERC20Ex for IERC20;
bytes32 public constant ROLE_SUPERVISOR = keccak256("ROLE_SUPERVISOR");
bytes32 public constant ROLE_PUBLISHER = keccak256("ROLE_PUBLISHER");
bytes32 public constant ROLE_UPDATER = keccak256("ROLE_UPDATER");
uint32 private constant MULTIPLIER_INCREMENT = PPM_RESOLUTION / 4;
uint32 private constant MAX_MULTIPLIER = PPM_RESOLUTION + MULTIPLIER_INCREMENT * 4;
uint8 private constant REWARDS_HALVING_FACTOR = 4;
uint256 private constant REWARD_RATE_FACTOR = 1e18;
uint256 private constant MAX_UINT256 = uint256(-1);
IStakingRewardsStore private immutable _store;
ITokenGovernance private immutable _networkTokenGovernance;
IERC20 private immutable _networkToken;
ICheckpointStore private immutable _lastRemoveTimes;
constructor(
IStakingRewardsStore store,
ITokenGovernance networkTokenGovernance,
ICheckpointStore lastRemoveTimes,
IContractRegistry registry
)
public
validAddress(address(store))
validAddress(address(networkTokenGovernance))
validAddress(address(lastRemoveTimes))
ContractRegistryClient(registry)
{
_store = store;
_networkTokenGovernance = networkTokenGovernance;
_networkToken = networkTokenGovernance.token();
_lastRemoveTimes = lastRemoveTimes;
_setRoleAdmin(ROLE_SUPERVISOR, ROLE_SUPERVISOR);
_setRoleAdmin(ROLE_PUBLISHER, ROLE_SUPERVISOR);
_setRoleAdmin(ROLE_UPDATER, ROLE_SUPERVISOR);
_setupRole(ROLE_SUPERVISOR, _msgSender());
}
modifier onlyPublisher() {
_onlyPublisher();
_;
}
function _onlyPublisher() internal view {
require(hasRole(ROLE_PUBLISHER, msg.sender), "ERR_ACCESS_DENIED");
}
modifier onlyUpdater() {
_onlyUpdater();
_;
}
function _onlyUpdater() internal view {
require(hasRole(ROLE_UPDATER, msg.sender), "ERR_ACCESS_DENIED");
}
function onAddingLiquidity(
address provider,
IConverterAnchor poolAnchor,
IReserveToken reserveToken,
uint256,
uint256
) external override onlyPublisher validExternalAddress(provider) {
IDSToken poolToken = IDSToken(address(poolAnchor));
PoolProgram memory program = _poolProgram(poolToken);
if (program.startTime == 0) {
return;
}
_updateRewards(provider, poolToken, reserveToken, program, _liquidityProtectionStats());
}
function onRemovingLiquidity(
uint256,
address provider,
IConverterAnchor,
IReserveToken,
uint256,
uint256
) external override onlyPublisher validExternalAddress(provider) {
ILiquidityProtectionStats lpStats = _liquidityProtectionStats();
_storeRewards(provider, lpStats.providerPools(provider), lpStats);
}
function store() external view override returns (IStakingRewardsStore) {
return _store;
}
function pendingRewards(address provider) external view override returns (uint256) {
return _pendingRewards(provider, _liquidityProtectionStats());
}
function pendingPoolRewards(address provider, IDSToken poolToken) external view override returns (uint256) {
return _pendingRewards(provider, poolToken, _liquidityProtectionStats());
}
function pendingReserveRewards(
address provider,
IDSToken poolToken,
IReserveToken reserveToken
) external view override returns (uint256) {
PoolProgram memory program = _poolProgram(poolToken);
return _pendingRewards(provider, poolToken, reserveToken, program, _liquidityProtectionStats());
}
function rewardsMultiplier(
address provider,
IDSToken poolToken,
IReserveToken reserveToken
) external view override returns (uint32) {
ProviderRewards memory providerRewards = _providerRewards(provider, poolToken, reserveToken);
PoolProgram memory program = _poolProgram(poolToken);
return _rewardsMultiplier(provider, providerRewards.effectiveStakingTime, program);
}
function totalClaimedRewards(address provider) external view override returns (uint256) {
uint256 totalRewards = 0;
ILiquidityProtectionStats lpStats = _liquidityProtectionStats();
IDSToken[] memory poolTokens = lpStats.providerPools(provider);
for (uint256 i = 0; i < poolTokens.length; ++i) {
IDSToken poolToken = poolTokens[i];
PoolProgram memory program = _poolProgram(poolToken);
for (uint256 j = 0; j < program.reserveTokens.length; ++j) {
IReserveToken reserveToken = program.reserveTokens[j];
ProviderRewards memory providerRewards = _providerRewards(provider, poolToken, reserveToken);
totalRewards = totalRewards.add(providerRewards.totalClaimedRewards);
}
}
return totalRewards;
}
function claimRewards() external override returns (uint256) {
return _claimPendingRewards(msg.sender, _liquidityProtectionStats());
}
function stakeRewards(uint256 maxAmount, IDSToken poolToken) external override returns (uint256, uint256) {
return _stakeRewards(msg.sender, maxAmount, poolToken, _liquidityProtectionStats());
}
function storePoolRewards(address[] calldata providers, IDSToken poolToken) external override onlyUpdater {
ILiquidityProtectionStats lpStats = _liquidityProtectionStats();
PoolProgram memory program = _poolProgram(poolToken);
for (uint256 i = 0; i < providers.length; ++i) {
for (uint256 j = 0; j < program.reserveTokens.length; ++j) {
_storeRewards(providers[i], poolToken, program.reserveTokens[j], program, lpStats, false);
}
}
}
function _pendingRewards(address provider, ILiquidityProtectionStats lpStats) private view returns (uint256) {
return _pendingRewards(provider, lpStats.providerPools(provider), lpStats);
}
function _pendingRewards(
address provider,
IDSToken[] memory poolTokens,
ILiquidityProtectionStats lpStats
) private view returns (uint256) {
uint256 reward = 0;
uint256 length = poolTokens.length;
for (uint256 i = 0; i < length; ++i) {
uint256 poolReward = _pendingRewards(provider, poolTokens[i], lpStats);
reward = reward.add(poolReward);
}
return reward;
}
function _pendingRewards(
address provider,
IDSToken poolToken,
ILiquidityProtectionStats lpStats
) private view returns (uint256) {
uint256 reward = 0;
PoolProgram memory program = _poolProgram(poolToken);
for (uint256 i = 0; i < program.reserveTokens.length; ++i) {
uint256 reserveReward = _pendingRewards(provider, poolToken, program.reserveTokens[i], program, lpStats);
reward = reward.add(reserveReward);
}
return reward;
}
function _pendingRewards(
address provider,
IDSToken poolToken,
IReserveToken reserveToken,
PoolProgram memory program,
ILiquidityProtectionStats lpStats
) private view returns (uint256) {
if (!_isProgramValid(reserveToken, program)) {
return 0;
}
PoolRewards memory poolRewardsData = _poolRewards(poolToken, reserveToken);
poolRewardsData.rewardPerToken = _rewardPerToken(poolToken, reserveToken, poolRewardsData, program, lpStats);
poolRewardsData.lastUpdateTime = Math.min(_time(), program.endTime);
ProviderRewards memory providerRewards = _providerRewards(provider, poolToken, reserveToken);
if (
providerRewards.effectiveStakingTime == 0 &&
lpStats.totalProviderAmount(provider, poolToken, reserveToken) == 0
) {
providerRewards.effectiveStakingTime = _time();
}
providerRewards.pendingBaseRewards = providerRewards.pendingBaseRewards.add(
_baseRewards(provider, poolToken, reserveToken, poolRewardsData, providerRewards, program, lpStats)
);
providerRewards.rewardPerToken = poolRewardsData.rewardPerToken;
(uint256 fullReward, ) =
_fullRewards(provider, poolToken, reserveToken, poolRewardsData, providerRewards, program, lpStats);
return fullReward;
}
function _claimPendingRewards(
address provider,
IDSToken[] memory poolTokens,
uint256 maxAmount,
ILiquidityProtectionStats lpStats,
bool resetStakingTime
) private returns (uint256) {
uint256 reward = 0;
uint256 length = poolTokens.length;
for (uint256 i = 0; i < length && maxAmount > 0; ++i) {
uint256 poolReward = _claimPendingRewards(provider, poolTokens[i], maxAmount, lpStats, resetStakingTime);
reward = reward.add(poolReward);
if (maxAmount != MAX_UINT256) {
maxAmount = maxAmount.sub(poolReward);
}
}
return reward;
}
function _claimPendingRewards(
address provider,
IDSToken poolToken,
uint256 maxAmount,
ILiquidityProtectionStats lpStats,
bool resetStakingTime
) private returns (uint256) {
uint256 reward = 0;
PoolProgram memory program = _poolProgram(poolToken);
for (uint256 i = 0; i < program.reserveTokens.length && maxAmount > 0; ++i) {
uint256 reserveReward =
_claimPendingRewards(
provider,
poolToken,
program.reserveTokens[i],
program,
maxAmount,
lpStats,
resetStakingTime
);
reward = reward.add(reserveReward);
if (maxAmount != MAX_UINT256) {
maxAmount = maxAmount.sub(reserveReward);
}
}
return reward;
}
function _claimPendingRewards(
address provider,
IDSToken poolToken,
IReserveToken reserveToken,
PoolProgram memory program,
uint256 maxAmount,
ILiquidityProtectionStats lpStats,
bool resetStakingTime
) private returns (uint256) {
(PoolRewards memory poolRewardsData, ProviderRewards memory providerRewards) =
_updateRewards(provider, poolToken, reserveToken, program, lpStats);
(uint256 fullReward, uint32 multiplier) =
_fullRewards(provider, poolToken, reserveToken, poolRewardsData, providerRewards, program, lpStats);
providerRewards.baseRewardsDebt = 0;
providerRewards.baseRewardsDebtMultiplier = 0;
if (maxAmount != MAX_UINT256 && fullReward > maxAmount) {
providerRewards.baseRewardsDebt = _removeMultiplier(fullReward.sub(maxAmount), multiplier);
providerRewards.baseRewardsDebtMultiplier = multiplier;
fullReward = maxAmount;
}
_store.updatePoolRewardsData(
poolToken,
reserveToken,
poolRewardsData.lastUpdateTime,
poolRewardsData.rewardPerToken,
poolRewardsData.totalClaimedRewards.add(fullReward)
);
_store.updateProviderRewardsData(
provider,
poolToken,
reserveToken,
providerRewards.rewardPerToken,
0,
providerRewards.totalClaimedRewards.add(fullReward),
resetStakingTime ? _time() : providerRewards.effectiveStakingTime,
providerRewards.baseRewardsDebt,
providerRewards.baseRewardsDebtMultiplier
);
return fullReward;
}
function _claimPendingRewards(address provider, ILiquidityProtectionStats lpStats) private returns (uint256) {
return _claimPendingRewards(provider, lpStats.providerPools(provider), MAX_UINT256, lpStats);
}
function _claimPendingRewards(
address provider,
IDSToken[] memory poolTokens,
uint256 maxAmount,
ILiquidityProtectionStats lpStats
) private returns (uint256) {
uint256 amount = _claimPendingRewards(provider, poolTokens, maxAmount, lpStats, true);
if (amount == 0) {
return amount;
}
_store.updateProviderLastClaimTime(provider);
_networkTokenGovernance.mint(provider, amount);
emit RewardsClaimed(provider, amount);
return amount;
}
function _stakeRewards(
address provider,
uint256 maxAmount,
IDSToken poolToken,
ILiquidityProtectionStats lpStats
) private returns (uint256, uint256) {
return _stakeRewards(provider, lpStats.providerPools(provider), maxAmount, poolToken, lpStats);
}
function _stakeRewards(
address provider,
IDSToken[] memory poolTokens,
uint256 maxAmount,
IDSToken newPoolToken,
ILiquidityProtectionStats lpStats
) private returns (uint256, uint256) {
uint256 amount = _claimPendingRewards(provider, poolTokens, maxAmount, lpStats, false);
if (amount == 0) {
return (amount, 0);
}
ILiquidityProtection liquidityProtection = _liquidityProtection();
address liquidityProtectionAddress = address(liquidityProtection);
_networkToken.ensureApprove(liquidityProtectionAddress, amount);
_networkTokenGovernance.mint(address(this), amount);
uint256 newId =
liquidityProtection.addLiquidityFor(provider, newPoolToken, IReserveToken(address(_networkToken)), amount);
emit RewardsStaked(provider, newPoolToken, amount, newId);
return (amount, newId);
}
function _storeRewards(
address provider,
IDSToken[] memory poolTokens,
ILiquidityProtectionStats lpStats
) private {
for (uint256 i = 0; i < poolTokens.length; ++i) {
IDSToken poolToken = poolTokens[i];
PoolProgram memory program = _poolProgram(poolToken);
for (uint256 j = 0; j < program.reserveTokens.length; ++j) {
_storeRewards(provider, poolToken, program.reserveTokens[j], program, lpStats, true);
}
}
}
function _storeRewards(
address provider,
IDSToken poolToken,
IReserveToken reserveToken,
PoolProgram memory program,
ILiquidityProtectionStats lpStats,
bool resetStakingTime
) private {
if (!_isProgramValid(reserveToken, program)) {
return;
}
(PoolRewards memory poolRewardsData, ProviderRewards memory providerRewards) =
_updateRewards(provider, poolToken, reserveToken, program, lpStats);
(uint256 fullReward, uint32 multiplier) =
_fullRewards(provider, poolToken, reserveToken, poolRewardsData, providerRewards, program, lpStats);
providerRewards.baseRewardsDebt = _removeMultiplier(fullReward, multiplier);
_store.updateProviderRewardsData(
provider,
poolToken,
reserveToken,
providerRewards.rewardPerToken,
0,
providerRewards.totalClaimedRewards,
resetStakingTime ? _time() : providerRewards.effectiveStakingTime,
providerRewards.baseRewardsDebt,
resetStakingTime ? multiplier : PPM_RESOLUTION
);
}
function _updateReserveRewards(
IDSToken poolToken,
IReserveToken reserveToken,
PoolProgram memory program,
ILiquidityProtectionStats lpStats
) private returns (PoolRewards memory) {
PoolRewards memory poolRewardsData = _poolRewards(poolToken, reserveToken);
bool update = false;
uint256 newRewardPerToken = _rewardPerToken(poolToken, reserveToken, poolRewardsData, program, lpStats);
if (poolRewardsData.rewardPerToken != newRewardPerToken) {
poolRewardsData.rewardPerToken = newRewardPerToken;
update = true;
}
uint256 newLastUpdateTime = Math.min(_time(), program.endTime);
if (poolRewardsData.lastUpdateTime != newLastUpdateTime) {
poolRewardsData.lastUpdateTime = newLastUpdateTime;
update = true;
}
if (update) {
_store.updatePoolRewardsData(
poolToken,
reserveToken,
poolRewardsData.lastUpdateTime,
poolRewardsData.rewardPerToken,
poolRewardsData.totalClaimedRewards
);
}
return poolRewardsData;
}
function _updateProviderRewards(
address provider,
IDSToken poolToken,
IReserveToken reserveToken,
PoolRewards memory poolRewardsData,
PoolProgram memory program,
ILiquidityProtectionStats lpStats
) private returns (ProviderRewards memory) {
ProviderRewards memory providerRewards = _providerRewards(provider, poolToken, reserveToken);
bool update = false;
if (
providerRewards.effectiveStakingTime == 0 &&
lpStats.totalProviderAmount(provider, poolToken, reserveToken) == 0
) {
providerRewards.effectiveStakingTime = _time();
update = true;
}
uint256 rewards =
_baseRewards(provider, poolToken, reserveToken, poolRewardsData, providerRewards, program, lpStats);
if (rewards != 0) {
providerRewards.pendingBaseRewards = providerRewards.pendingBaseRewards.add(rewards);
update = true;
}
if (providerRewards.rewardPerToken != poolRewardsData.rewardPerToken) {
providerRewards.rewardPerToken = poolRewardsData.rewardPerToken;
update = true;
}
if (update) {
_store.updateProviderRewardsData(
provider,
poolToken,
reserveToken,
providerRewards.rewardPerToken,
providerRewards.pendingBaseRewards,
providerRewards.totalClaimedRewards,
providerRewards.effectiveStakingTime,
providerRewards.baseRewardsDebt,
providerRewards.baseRewardsDebtMultiplier
);
}
return providerRewards;
}
function _updateRewards(
address provider,
IDSToken poolToken,
IReserveToken reserveToken,
PoolProgram memory program,
ILiquidityProtectionStats lpStats
) private returns (PoolRewards memory, ProviderRewards memory) {
PoolRewards memory poolRewardsData = _updateReserveRewards(poolToken, reserveToken, program, lpStats);
ProviderRewards memory providerRewards =
_updateProviderRewards(provider, poolToken, reserveToken, poolRewardsData, program, lpStats);
return (poolRewardsData, providerRewards);
}
function _rewardPerToken(
IDSToken poolToken,
IReserveToken reserveToken,
PoolRewards memory poolRewardsData,
PoolProgram memory program,
ILiquidityProtectionStats lpStats
) private view returns (uint256) {
uint256 totalReserveAmount = lpStats.totalReserveAmount(poolToken, reserveToken);
if (totalReserveAmount == 0) {
return poolRewardsData.rewardPerToken;
}
uint256 currentTime = _time();
if (currentTime < program.startTime) {
return 0;
}
uint256 stakingEndTime = Math.min(currentTime, program.endTime);
uint256 stakingStartTime = Math.max(program.startTime, poolRewardsData.lastUpdateTime);
if (stakingStartTime == stakingEndTime) {
return poolRewardsData.rewardPerToken;
}
return
poolRewardsData.rewardPerToken.add(
stakingEndTime
.sub(stakingStartTime)
.mul(program.rewardRate)
.mul(REWARD_RATE_FACTOR)
.mul(_rewardShare(reserveToken, program))
.div(totalReserveAmount.mul(PPM_RESOLUTION))
);
}
function _baseRewards(
address provider,
IDSToken poolToken,
IReserveToken reserveToken,
PoolRewards memory poolRewardsData,
ProviderRewards memory providerRewards,
PoolProgram memory program,
ILiquidityProtectionStats lpStats
) private view returns (uint256) {
uint256 totalProviderAmount = lpStats.totalProviderAmount(provider, poolToken, reserveToken);
uint256 newRewardPerToken = _rewardPerToken(poolToken, reserveToken, poolRewardsData, program, lpStats);
return
totalProviderAmount
.mul(newRewardPerToken.sub(providerRewards.rewardPerToken))
.div(REWARD_RATE_FACTOR);
}
function _fullRewards(
address provider,
IDSToken poolToken,
IReserveToken reserveToken,
PoolRewards memory poolRewardsData,
ProviderRewards memory providerRewards,
PoolProgram memory program,
ILiquidityProtectionStats lpStats
) private view returns (uint256, uint32) {
uint256 newBaseRewards =
_baseRewards(provider, poolToken, reserveToken, poolRewardsData, providerRewards, program, lpStats);
_verifyBaseReward(newBaseRewards, providerRewards.effectiveStakingTime, reserveToken, program);
uint32 multiplier = _rewardsMultiplier(provider, providerRewards.effectiveStakingTime, program);
uint256 fullReward = _applyMultiplier(providerRewards.pendingBaseRewards.add(newBaseRewards), multiplier);
fullReward = fullReward.add(
_applyHigherMultiplier(
providerRewards.baseRewardsDebt,
multiplier,
providerRewards.baseRewardsDebtMultiplier
)
);
_verifyFullReward(fullReward, reserveToken, poolRewardsData, program);
return (fullReward, multiplier);
}
function _rewardShare(IReserveToken reserveToken, PoolProgram memory program) private pure returns (uint32) {
if (reserveToken == program.reserveTokens[0]) {
return program.rewardShares[0];
}
return program.rewardShares[1];
}
function _rewardsMultiplier(
address provider,
uint256 stakingStartTime,
PoolProgram memory program
) private view returns (uint32) {
uint256 effectiveStakingEndTime = Math.min(_time(), program.endTime);
uint256 effectiveStakingStartTime =
Math.max(
Math.max(stakingStartTime, program.startTime),
Math.max(_lastRemoveTimes.checkpoint(provider), _store.providerLastClaimTime(provider))
);
if (effectiveStakingStartTime >= effectiveStakingEndTime) {
return PPM_RESOLUTION;
}
uint256 effectiveStakingDuration = effectiveStakingEndTime.sub(effectiveStakingStartTime);
return PPM_RESOLUTION + MULTIPLIER_INCREMENT * uint32(Math.min(effectiveStakingDuration.div(1 weeks), 4));
}
function _poolProgram(IDSToken poolToken) private view returns (PoolProgram memory) {
PoolProgram memory program;
(program.startTime, program.endTime, program.rewardRate, program.reserveTokens, program.rewardShares) = _store
.poolProgram(poolToken);
return program;
}
function _poolRewards(IDSToken poolToken, IReserveToken reserveToken) private view returns (PoolRewards memory) {
PoolRewards memory data;
(data.lastUpdateTime, data.rewardPerToken, data.totalClaimedRewards) = _store.poolRewards(
poolToken,
reserveToken
);
return data;
}
function _providerRewards(
address provider,
IDSToken poolToken,
IReserveToken reserveToken
) private view returns (ProviderRewards memory) {
ProviderRewards memory data;
(
data.rewardPerToken,
data.pendingBaseRewards,
data.totalClaimedRewards,
data.effectiveStakingTime,
data.baseRewardsDebt,
data.baseRewardsDebtMultiplier
) = _store.providerRewards(provider, poolToken, reserveToken);
return data;
}
function _applyMultiplier(uint256 amount, uint32 multiplier) private pure returns (uint256) {
if (multiplier == PPM_RESOLUTION) {
return amount;
}
return amount.mul(multiplier).div(PPM_RESOLUTION);
}
function _removeMultiplier(uint256 amount, uint32 multiplier) private pure returns (uint256) {
if (multiplier == PPM_RESOLUTION) {
return amount;
}
return amount.mul(PPM_RESOLUTION).div(multiplier);
}
function _applyHigherMultiplier(
uint256 amount,
uint32 multiplier1,
uint32 multiplier2
) private pure returns (uint256) {
return _applyMultiplier(amount, multiplier1 > multiplier2 ? multiplier1 : multiplier2);
}
function _verifyBaseReward(
uint256 baseReward,
uint256 stakingStartTime,
IReserveToken reserveToken,
PoolProgram memory program
) private view {
uint256 currentTime = _time();
if (currentTime < program.startTime || stakingStartTime >= program.endTime) {
require(baseReward == 0, "ERR_BASE_REWARD_TOO_HIGH");
return;
}
uint256 effectiveStakingStartTime = Math.max(stakingStartTime, program.startTime);
uint256 effectiveStakingEndTime = Math.min(currentTime, program.endTime);
require(
baseReward <=
(program.rewardRate * REWARDS_HALVING_FACTOR)
.mul(effectiveStakingEndTime.sub(effectiveStakingStartTime))
.mul(_rewardShare(reserveToken, program))
.div(PPM_RESOLUTION),
"ERR_BASE_REWARD_RATE_TOO_HIGH"
);
}
function _verifyFullReward(
uint256 fullReward,
IReserveToken reserveToken,
PoolRewards memory poolRewardsData,
PoolProgram memory program
) private pure {
uint256 maxClaimableReward =
(
(program.rewardRate * REWARDS_HALVING_FACTOR)
.mul(program.endTime.sub(program.startTime))
.mul(_rewardShare(reserveToken, program))
.mul(MAX_MULTIPLIER)
.div(PPM_RESOLUTION)
.div(PPM_RESOLUTION)
)
.sub(poolRewardsData.totalClaimedRewards);
require(fullReward <= maxClaimableReward, "ERR_REWARD_RATE_TOO_HIGH");
}
function _liquidityProtectionStats() private view returns (ILiquidityProtectionStats) {
return _liquidityProtection().stats();
}
function _liquidityProtection() private view returns (ILiquidityProtection) {
return ILiquidityProtection(_addressOf(LIQUIDITY_PROTECTION));
}
function _isProgramValid(IReserveToken reserveToken, PoolProgram memory program) private pure returns (bool) {
return
address(reserveToken) != address(0) &&
(program.reserveTokens[0] == reserveToken || program.reserveTokens[1] == reserveToken);
}
}
文件 33 的 34:Time.sol
pragma solidity 0.6.12;
contract Time {
function _time() internal view virtual returns (uint256) {
return block.timestamp;
}
}
文件 34 的 34:Utils.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract Utils {
uint32 internal constant PPM_RESOLUTION = 1000000;
modifier greaterThanZero(uint256 value) {
_greaterThanZero(value);
_;
}
function _greaterThanZero(uint256 value) internal pure {
require(value > 0, "ERR_ZERO_VALUE");
}
modifier validAddress(address addr) {
_validAddress(addr);
_;
}
function _validAddress(address addr) internal pure {
require(addr != address(0), "ERR_INVALID_ADDRESS");
}
modifier validPortion(uint32 _portion) {
_validPortion(_portion);
_;
}
function _validPortion(uint32 _portion) internal pure {
require(_portion > 0 && _portion <= PPM_RESOLUTION, "ERR_INVALID_PORTION");
}
modifier validExternalAddress(address addr) {
_validExternalAddress(addr);
_;
}
function _validExternalAddress(address addr) internal view {
require(addr != address(0) && addr != address(this), "ERR_INVALID_EXTERNAL_ADDRESS");
}
modifier validFee(uint32 fee) {
_validFee(fee);
_;
}
function _validFee(uint32 fee) internal pure {
require(fee <= PPM_RESOLUTION, "ERR_INVALID_FEE");
}
}
{
"compilationTarget": {
"contracts/staking-rewards/StakingRewards.sol": "StakingRewards"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"contract IStakingRewardsStore","name":"store","type":"address"},{"internalType":"contract ITokenGovernance","name":"networkTokenGovernance","type":"address"},{"internalType":"contract ICheckpointStore","name":"lastRemoveTimes","type":"address"},{"internalType":"contract IContractRegistry","name":"registry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":true,"internalType":"contract IDSToken","name":"poolToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newId","type":"uint256"}],"name":"RewardsStaked","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"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLE_PUBLISHER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLE_SUPERVISOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLE_UPDATER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"newOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"provider","type":"address"},{"internalType":"contract IConverterAnchor","name":"poolAnchor","type":"address"},{"internalType":"contract IReserveToken","name":"reserveToken","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"onAddingLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"provider","type":"address"},{"internalType":"contract IConverterAnchor","name":"","type":"address"},{"internalType":"contract IReserveToken","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"onRemovingLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"onlyOwnerCanUpdateRegistry","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"provider","type":"address"},{"internalType":"contract IDSToken","name":"poolToken","type":"address"}],"name":"pendingPoolRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"provider","type":"address"},{"internalType":"contract IDSToken","name":"poolToken","type":"address"},{"internalType":"contract IReserveToken","name":"reserveToken","type":"address"}],"name":"pendingReserveRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"provider","type":"address"}],"name":"pendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"prevRegistry","outputs":[{"internalType":"contract IContractRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract IContractRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"restoreRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"restrictOwnerOnly","type":"bool"}],"name":"restrictRegistryUpdate","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":"provider","type":"address"},{"internalType":"contract IDSToken","name":"poolToken","type":"address"},{"internalType":"contract IReserveToken","name":"reserveToken","type":"address"}],"name":"rewardsMultiplier","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxAmount","type":"uint256"},{"internalType":"contract IDSToken","name":"poolToken","type":"address"}],"name":"stakeRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"store","outputs":[{"internalType":"contract IStakingRewardsStore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"providers","type":"address[]"},{"internalType":"contract IDSToken","name":"poolToken","type":"address"}],"name":"storePoolRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"provider","type":"address"}],"name":"totalClaimedRewards","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":[],"name":"updateRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"}]