编译器
0.6.12+commit.27d51765
文件 1 的 31: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);
}
}
}
}
文件 2 的 31:IClaimable.sol
pragma solidity >=0.6.12;
interface IClaimable {
function owner() external view returns (address);
function transferOwnership(address newOwner) external;
function acceptOwnership() external;
}
文件 3 的 31:IConverter.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IConverterAnchor.sol";
import "../../utility/interfaces/IOwned.sol";
import "../../token/interfaces/IReserveToken.sol";
interface IConverter is IOwned {
function converterType() external pure returns (uint16);
function anchor() external view returns (IConverterAnchor);
function isActive() external view returns (bool);
function targetAmountAndFee(
IReserveToken sourceToken,
IReserveToken targetToken,
uint256 sourceAmount
) external view returns (uint256, uint256);
function convert(
IReserveToken sourceToken,
IReserveToken targetToken,
uint256 sourceAmount,
address trader,
address payable beneficiary
) external payable returns (uint256);
function conversionFee() external view returns (uint32);
function maxConversionFee() external view returns (uint32);
function reserveBalance(IReserveToken reserveToken) external view returns (uint256);
receive() external payable;
function transferAnchorOwnership(address newOwner) external;
function acceptAnchorOwnership() external;
function setConversionFee(uint32 fee) external;
function addReserve(IReserveToken token, uint32 weight) external;
function transferReservesOnUpgrade(address newConverter) external;
function onUpgradeComplete() external;
function token() external view returns (IConverterAnchor);
function transferTokenOwnership(address newOwner) external;
function acceptTokenOwnership() external;
function reserveTokenCount() external view returns (uint16);
function reserveTokens() external view returns (IReserveToken[] memory);
function connectors(IReserveToken reserveToken)
external
view
returns (
uint256,
uint32,
bool,
bool,
bool
);
function getConnectorBalance(IReserveToken connectorToken) external view returns (uint256);
function connectorTokens(uint256 index) external view returns (IReserveToken);
function connectorTokenCount() external view returns (uint16);
event Activation(uint16 indexed converterType, IConverterAnchor indexed anchor, bool indexed activated);
event Conversion(
IReserveToken indexed sourceToken,
IReserveToken indexed targetToken,
address indexed trader,
uint256 sourceAmount,
uint256 targetAmount,
int256 conversionFee
);
event TokenRateUpdate(address indexed token1, address indexed token2, uint256 rateN, uint256 rateD);
event ConversionFeeUpdate(uint32 prevFee, uint32 newFee);
}
文件 4 的 31:IConverterAnchor.sol
pragma solidity 0.6.12;
import "../../utility/interfaces/IOwned.sol";
interface IConverterAnchor is IOwned {
}
文件 5 的 31:IConverterRegistry.sol
pragma solidity 0.6.12;
import "../../token/interfaces/IReserveToken.sol";
import "./IConverterAnchor.sol";
interface IConverterRegistry {
function getAnchorCount() external view returns (uint256);
function getAnchors() external view returns (address[] memory);
function getAnchor(uint256 index) external view returns (IConverterAnchor);
function isAnchor(address value) external view returns (bool);
function getLiquidityPoolCount() external view returns (uint256);
function getLiquidityPools() external view returns (address[] memory);
function getLiquidityPool(uint256 index) external view returns (IConverterAnchor);
function isLiquidityPool(address value) external view returns (bool);
function getConvertibleTokenCount() external view returns (uint256);
function getConvertibleTokens() external view returns (address[] memory);
function getConvertibleToken(uint256 index) external view returns (IReserveToken);
function isConvertibleToken(address value) external view returns (bool);
function getConvertibleTokenAnchorCount(IReserveToken convertibleToken) external view returns (uint256);
function getConvertibleTokenAnchors(IReserveToken convertibleToken) external view returns (address[] memory);
function getConvertibleTokenAnchor(IReserveToken convertibleToken, uint256 index)
external
view
returns (IConverterAnchor);
function isConvertibleTokenAnchor(IReserveToken convertibleToken, address value) external view returns (bool);
function getLiquidityPoolByConfig(
uint16 converterType,
IReserveToken[] memory reserveTokens,
uint32[] memory reserveWeights
) external view returns (IConverterAnchor);
}
文件 6 的 31: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;
}
文件 7 的 31: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);
}
文件 8 的 31: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 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);
}
文件 9 的 31: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);
}
文件 10 的 31: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);
}
文件 11 的 31: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;
}
文件 12 的 31: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;
}
文件 13 的 31: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;
}
文件 14 的 31: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;
}
文件 15 的 31:IOwned.sol
pragma solidity 0.6.12;
interface IOwned {
function owner() external view returns (address);
function transferOwnership(address newOwner) external;
function acceptOwnership() external;
}
文件 16 的 31:IReserveToken.sol
pragma solidity 0.6.12;
interface IReserveToken {
}
文件 17 的 31: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;
}
文件 18 的 31: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;
}
文件 19 的 31:ITransferPositionCallback.sol
pragma solidity 0.6.12;
interface ITransferPositionCallback {
function onTransferPosition(
uint256 newId,
address provider,
bytes calldata data
) external;
}
文件 20 的 31:LiquidityProtection.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@bancor/token-governance/contracts/ITokenGovernance.sol";
import "../utility/MathEx.sol";
import "../utility/Types.sol";
import "../utility/Time.sol";
import "../utility/Utils.sol";
import "../utility/Owned.sol";
import "../token/interfaces/IDSToken.sol";
import "../token/ReserveToken.sol";
import "../converter/interfaces/IConverterAnchor.sol";
import "../converter/interfaces/IConverter.sol";
import "../converter/interfaces/IConverterRegistry.sol";
import "./interfaces/ILiquidityProtection.sol";
interface ILiquidityPoolConverter is IConverter {
function addLiquidity(
IReserveToken[] memory reserveTokens,
uint256[] memory reserveAmounts,
uint256 minReturn
) external payable;
function removeLiquidity(
uint256 amount,
IReserveToken[] memory reserveTokens,
uint256[] memory reserveMinReturnAmounts
) external returns (uint256[] memory);
function recentAverageRate(IReserveToken reserveToken) external view returns (uint256, uint256);
}
contract LiquidityProtection is ILiquidityProtection, Utils, Owned, ReentrancyGuard, Time {
using Math for uint256;
using SafeMath for uint256;
using ReserveToken for IReserveToken;
using SafeERC20 for IERC20;
using SafeERC20 for IDSToken;
using SafeERC20Ex for IERC20;
using Address for address payable;
struct Position {
address provider;
IDSToken poolToken;
IReserveToken reserveToken;
uint256 poolAmount;
uint256 reserveAmount;
uint256 reserveRateN;
uint256 reserveRateD;
uint256 timestamp;
}
struct PackedRates {
uint128 addSpotRateN;
uint128 addSpotRateD;
uint128 removeSpotRateN;
uint128 removeSpotRateD;
uint128 removeAverageRateN;
uint128 removeAverageRateD;
}
uint256 internal constant MAX_UINT128 = 2**128 - 1;
uint256 internal constant MAX_UINT256 = uint256(-1);
address payable private immutable _vaultV3;
ILiquidityProtectionSettings private immutable _settings;
ILiquidityProtectionStore private immutable _store;
ILiquidityProtectionStats private immutable _stats;
ILiquidityProtectionSystemStore private immutable _systemStore;
ITokenHolder private immutable _wallet;
IERC20 private immutable _networkToken;
ITokenGovernance private immutable _networkTokenGovernance;
IERC20 private immutable _govToken;
ITokenGovernance private immutable _govTokenGovernance;
mapping(IConverterAnchor => uint256) private _totalPositionsValue;
bool private _addingEnabled = false;
bool private _removingEnabled = false;
constructor(
address payable vaultV3,
ILiquidityProtectionSettings settings,
ILiquidityProtectionStore store,
ILiquidityProtectionStats stats,
ILiquidityProtectionSystemStore systemStore,
ITokenHolder wallet,
ITokenGovernance networkTokenGovernance,
ITokenGovernance govTokenGovernance
) public {
_validAddress(address(vaultV3));
_validAddress(address(settings));
_validAddress(address(store));
_validAddress(address(stats));
_validAddress(address(systemStore));
_validAddress(address(wallet));
_vaultV3 = vaultV3;
_settings = settings;
_store = store;
_stats = stats;
_systemStore = systemStore;
_wallet = wallet;
_networkTokenGovernance = networkTokenGovernance;
_govTokenGovernance = govTokenGovernance;
_networkToken = networkTokenGovernance.token();
_govToken = govTokenGovernance.token();
}
modifier poolSupportedAndWhitelisted(IConverterAnchor poolAnchor) {
_poolSupported(poolAnchor);
_poolWhitelisted(poolAnchor);
_;
}
modifier addLiquidityEnabled(IConverterAnchor poolAnchor, IReserveToken reserveToken) {
_addLiquidityEnabled(poolAnchor, reserveToken);
_;
}
modifier removeLiquidityEnabled() {
_removeLiquidityEnabled();
_;
}
function _poolSupported(IConverterAnchor poolAnchor) internal view {
require(_settings.isPoolSupported(poolAnchor), "ERR_POOL_NOT_SUPPORTED");
}
function _poolWhitelisted(IConverterAnchor poolAnchor) internal view {
require(_settings.isPoolWhitelisted(poolAnchor), "ERR_POOL_NOT_WHITELISTED");
}
function _addLiquidityEnabled(IConverterAnchor poolAnchor, IReserveToken reserveToken) internal view {
require(
_addingEnabled && !_settings.addLiquidityDisabled(poolAnchor, reserveToken),
"ERR_ADD_LIQUIDITY_DISABLED"
);
}
function _removeLiquidityEnabled() internal view {
require(_removingEnabled);
}
function _verifyEthAmount(uint256 value) internal view {
require(msg.value == value, "ERR_ETH_AMOUNT_MISMATCH");
}
function store() external view override returns (ILiquidityProtectionStore) {
return _store;
}
function stats() external view override returns (ILiquidityProtectionStats) {
return _stats;
}
function settings() external view override returns (ILiquidityProtectionSettings) {
return _settings;
}
receive() external payable {}
function transferStoreOwnership(address newOwner) external ownerOnly {
_store.transferOwnership(newOwner);
}
function acceptStoreOwnership() external ownerOnly {
_store.acceptOwnership();
}
function transferWalletOwnership(address newOwner) external ownerOnly {
_wallet.transferOwnership(newOwner);
}
function acceptWalletOwnership() external ownerOnly {
_wallet.acceptOwnership();
}
function addLiquidityFor(
address owner,
IConverterAnchor poolAnchor,
IReserveToken reserveToken,
uint256 amount
)
external
payable
override
nonReentrant
validAddress(owner)
poolSupportedAndWhitelisted(poolAnchor)
addLiquidityEnabled(poolAnchor, reserveToken)
greaterThanZero(amount)
returns (uint256)
{
return _addLiquidity(owner, poolAnchor, reserveToken, amount);
}
function addLiquidity(
IConverterAnchor poolAnchor,
IReserveToken reserveToken,
uint256 amount
)
external
payable
override
nonReentrant
poolSupportedAndWhitelisted(poolAnchor)
addLiquidityEnabled(poolAnchor, reserveToken)
greaterThanZero(amount)
returns (uint256)
{
return _addLiquidity(msg.sender, poolAnchor, reserveToken, amount);
}
function _addLiquidity(
address owner,
IConverterAnchor poolAnchor,
IReserveToken reserveToken,
uint256 amount
) private returns (uint256) {
if (_isNetworkToken(reserveToken)) {
_verifyEthAmount(0);
return _addNetworkTokenLiquidity(owner, poolAnchor, amount);
}
_verifyEthAmount(reserveToken.isNativeToken() ? amount : 0);
return _addBaseTokenLiquidity(owner, poolAnchor, reserveToken, amount);
}
function _addNetworkTokenLiquidity(
address owner,
IConverterAnchor poolAnchor,
uint256 amount
) internal returns (uint256) {
IDSToken poolToken = IDSToken(address(poolAnchor));
IReserveToken networkToken = IReserveToken(address(_networkToken));
Fraction memory poolRate = _poolTokenRate(poolToken, networkToken);
uint256 poolTokenAmount = _mulDivF(amount, poolRate.d, poolRate.n);
_systemStore.decSystemBalance(poolToken, poolTokenAmount);
uint256 id = _addPosition(owner, poolToken, networkToken, poolTokenAmount, amount, _time());
_networkToken.safeTransferFrom(msg.sender, address(this), amount);
_burnNetworkTokens(poolAnchor, amount);
_govTokenGovernance.mint(owner, amount);
return id;
}
function _addBaseTokenLiquidity(
address owner,
IConverterAnchor poolAnchor,
IReserveToken baseToken,
uint256 amount
) internal returns (uint256) {
IDSToken poolToken = IDSToken(address(poolAnchor));
IReserveToken networkToken = IReserveToken(address(_networkToken));
ILiquidityPoolConverter converter = ILiquidityPoolConverter(payable(_ownedBy(poolAnchor)));
(uint256 reserveBalanceBase, uint256 reserveBalanceNetwork) = _converterReserveBalances(
converter,
baseToken,
networkToken
);
require(reserveBalanceNetwork >= _settings.minNetworkTokenLiquidityForMinting(), "ERR_NOT_ENOUGH_LIQUIDITY");
uint256 newNetworkLiquidityAmount = _mulDivF(amount, reserveBalanceNetwork, reserveBalanceBase);
uint256 mintingLimit = _networkTokenMintingLimit(poolAnchor);
uint256 newNetworkTokensMinted = _systemStore.networkTokensMinted(poolAnchor).add(newNetworkLiquidityAmount);
require(newNetworkTokensMinted <= mintingLimit, "ERR_MAX_AMOUNT_REACHED");
_mintNetworkTokens(address(this), poolAnchor, newNetworkLiquidityAmount);
networkToken.ensureApprove(address(converter), newNetworkLiquidityAmount);
if (!baseToken.isNativeToken()) {
baseToken.safeTransferFrom(msg.sender, address(this), amount);
baseToken.ensureApprove(address(converter), amount);
}
_addLiquidity(converter, baseToken, networkToken, amount, newNetworkLiquidityAmount, msg.value);
uint256 poolTokenAmount = poolToken.balanceOf(address(this));
poolToken.safeTransfer(address(_wallet), poolTokenAmount);
_systemStore.incSystemBalance(poolToken, poolTokenAmount - poolTokenAmount / 2);
return _addPosition(owner, poolToken, baseToken, poolTokenAmount / 2, amount, _time());
}
function poolAvailableSpace(IConverterAnchor poolAnchor)
external
view
poolSupportedAndWhitelisted(poolAnchor)
returns (uint256, uint256)
{
return (_baseTokenAvailableSpace(poolAnchor), _networkTokenAvailableSpace(poolAnchor));
}
function _baseTokenAvailableSpace(IConverterAnchor poolAnchor) internal view returns (uint256) {
ILiquidityPoolConverter converter = ILiquidityPoolConverter(payable(_ownedBy(poolAnchor)));
IReserveToken networkToken = IReserveToken(address(_networkToken));
IReserveToken baseToken = _converterOtherReserve(converter, networkToken);
(uint256 reserveBalanceBase, uint256 reserveBalanceNetwork) = _converterReserveBalances(
converter,
baseToken,
networkToken
);
uint256 mintingLimit = _networkTokenMintingLimit(poolAnchor);
uint256 networkTokensMinted = _systemStore.networkTokensMinted(poolAnchor);
uint256 networkTokensCanBeMinted = Math.max(mintingLimit, networkTokensMinted) - networkTokensMinted;
return _mulDivF(networkTokensCanBeMinted, reserveBalanceBase, reserveBalanceNetwork);
}
function _networkTokenAvailableSpace(IConverterAnchor poolAnchor) internal view returns (uint256) {
IDSToken poolToken = IDSToken(address(poolAnchor));
IReserveToken networkToken = IReserveToken(address(_networkToken));
Fraction memory poolRate = _poolTokenRate(poolToken, networkToken);
return _systemStore.systemBalance(poolToken).mul(poolRate.n).add(poolRate.n).sub(1).div(poolRate.d);
}
function removeLiquidityReturn(
uint256 id,
uint32 portion,
uint256 removeTimestamp
)
external
view
validPortion(portion)
returns (
uint256,
uint256,
uint256
)
{
Position memory pos = _position(id);
require(pos.provider != address(0), "ERR_INVALID_ID");
require(removeTimestamp >= pos.timestamp, "ERR_INVALID_TIMESTAMP");
if (portion != PPM_RESOLUTION) {
(pos.poolAmount, pos.reserveAmount) = _portionAmounts(pos.poolAmount, pos.reserveAmount, portion);
}
PackedRates memory packedRates = _packRates(
pos.poolToken,
pos.reserveToken,
pos.reserveRateN,
pos.reserveRateD
);
(uint256 targetAmount,) = _removeLiquidityAmounts(
pos.poolToken,
pos.reserveToken,
pos.poolAmount,
pos.reserveAmount,
packedRates
);
return (targetAmount, targetAmount, 0);
}
function removeLiquidity(uint256 id, uint32 portion)
external
override
nonReentrant
removeLiquidityEnabled
validPortion(portion)
{
_removeLiquidity(msg.sender, id, portion);
}
function _removeLiquidity(
address payable provider,
uint256 id,
uint32 portion
) internal {
require(portion == PPM_RESOLUTION, "ERR_PORTION_NOT_SUPPORTED");
Position memory removedPos = _removePosition(provider, id, portion);
_systemStore.incSystemBalance(removedPos.poolToken, removedPos.poolAmount);
if (_isNetworkToken(removedPos.reserveToken)) {
_govToken.safeTransferFrom(provider, address(this), removedPos.reserveAmount);
_govTokenGovernance.burn(removedPos.reserveAmount);
}
PackedRates memory packedRates = _packRates(
removedPos.poolToken,
removedPos.reserveToken,
removedPos.reserveRateN,
removedPos.reserveRateD
);
_verifyRateDeviation(
packedRates.removeSpotRateN,
packedRates.removeSpotRateD,
packedRates.removeAverageRateN,
packedRates.removeAverageRateD
);
(uint256 targetAmount, uint256 posValue) = _removeLiquidityAmounts(
removedPos.poolToken,
removedPos.reserveToken,
removedPos.poolAmount,
removedPos.reserveAmount,
packedRates
);
if (_isNetworkToken(removedPos.reserveToken)) {
_mintNetworkTokens(address(_wallet), removedPos.poolToken, targetAmount);
_lockTokens(provider, targetAmount);
return;
}
Fraction memory poolRate = _poolTokenRate(removedPos.poolToken, removedPos.reserveToken);
uint256 poolAmount = _liquidationAmount(targetAmount, poolRate, removedPos.poolToken);
_withdrawPoolTokens(removedPos.poolToken, poolAmount);
_removeLiquidity(
removedPos.poolToken,
poolAmount,
removedPos.reserveToken,
IReserveToken(address(_networkToken))
);
uint256 totalValue = _totalPositionsValue[removedPos.poolToken];
_totalPositionsValue[removedPos.poolToken] = Math.max(totalValue, posValue).sub(posValue);
uint256 baseBalance = removedPos.reserveToken.balanceOf(address(this));
removedPos.reserveToken.safeTransfer(provider, baseBalance);
uint256 networkBalance = _networkToken.balanceOf(address(this));
if (networkBalance > 0) {
_burnNetworkTokens(removedPos.poolToken, networkBalance);
}
}
function positionValue(uint256 id) external view returns (uint256) {
Position memory pos = _position(id);
PackedRates memory packedRates = _packRates(
pos.poolToken,
pos.reserveToken,
pos.reserveRateN,
pos.reserveRateD
);
(, uint256 posValue) = _removeLiquidityAmounts(
pos.poolToken,
pos.reserveToken,
pos.poolAmount,
pos.reserveAmount,
packedRates
);
return posValue;
}
function _removeLiquidityAmounts(
IDSToken poolToken,
IReserveToken reserveToken,
uint256 poolAmount,
uint256 reserveAmount,
PackedRates memory packedRates
) internal view returns (uint256, uint256) {
uint256 targetAmount;
Fraction memory addSpotRate = Fraction({ n: packedRates.addSpotRateN, d: packedRates.addSpotRateD });
Fraction memory removeSpotRate = Fraction({ n: packedRates.removeSpotRateN, d: packedRates.removeSpotRateD });
Fraction memory poolRate = _poolTokenRate(poolToken, reserveToken);
targetAmount = _protectedAmountPlusFee(poolAmount, poolRate, addSpotRate, removeSpotRate);
if (_isNetworkToken(reserveToken)) {
return (targetAmount, targetAmount);
}
Fraction memory removeAverageRate = Fraction({
n: packedRates.removeAverageRateN,
d: packedRates.removeAverageRateD
});
Fraction memory loss = _impLoss(addSpotRate, removeAverageRate);
targetAmount = _deductIL(Math.max(reserveAmount, targetAmount), loss);
Fraction memory poolDeficit = _poolDeficit(poolToken);
Fraction memory availablePortion = Fraction({ n: poolDeficit.d - poolDeficit.n, d: poolDeficit.d});
return (_mulDivF(targetAmount, availablePortion.n, availablePortion.d), targetAmount);
}
function poolDeficitPPM(IDSToken poolToken)
external
view
returns (uint256)
{
Fraction memory poolDeficit = _poolDeficit(poolToken);
return _mulDivF(PPM_RESOLUTION, poolDeficit.n, poolDeficit.d);
}
function _poolDeficit(IDSToken poolToken)
private
view
returns (Fraction memory)
{
IConverter converter = IConverter(payable(_ownedBy(poolToken)));
IReserveToken reserveToken = _converterOtherReserve(converter, IReserveToken(address(_networkToken)));
uint256 reserveBalance = converter.reserveBalance(reserveToken);
uint256 poolTokenSupply = poolToken.totalSupply();
uint256 protectedPoolTokenAmount = poolToken.balanceOf(address(_wallet));
uint256 protectedLiquidity = _mulDivF(reserveBalance, protectedPoolTokenAmount, poolTokenSupply);
uint256 totalValue = totalPositionsValue(poolToken);
if (protectedLiquidity >= totalValue) {
return Fraction({ n: 0, d: 1 });
}
return Fraction({
n: totalValue.sub(protectedLiquidity),
d: totalValue
});
}
function transferPosition(uint256 id, address newProvider)
external
override
nonReentrant
validAddress(newProvider)
returns (uint256)
{
return _transferPosition(msg.sender, id, newProvider);
}
function transferPositionAndNotify(
uint256 id,
address newProvider,
ITransferPositionCallback callback,
bytes calldata data
) external override nonReentrant validAddress(newProvider) validAddress(address(callback)) returns (uint256) {
uint256 newId = _transferPosition(msg.sender, id, newProvider);
callback.onTransferPosition(newId, msg.sender, data);
return newId;
}
function migrateSystemPoolTokens(IConverterAnchor[] calldata poolAnchors) external nonReentrant ownerOnly {
uint256 length = poolAnchors.length;
for (uint256 i = 0; i < length; i++) {
IConverterAnchor poolAnchor = poolAnchors[i];
IDSToken poolToken = IDSToken(address(poolAnchor));
ILiquidityPoolConverter converter = ILiquidityPoolConverter(payable(_ownedBy(poolToken)));
IReserveToken reserveToken1 = IReserveToken(address(_networkToken));
IReserveToken reserveToken2 = _converterOtherReserve(converter, IReserveToken(address(_networkToken)));
uint256 poolAmount = _poolTokensToMigrate(poolToken, converter, reserveToken2);
if (poolAmount == 0) {
continue;
}
_withdrawPoolTokens(poolToken, poolAmount);
(IReserveToken[] memory reserveTokens, uint256[] memory minReturns) = _removeLiquidityInput(
reserveToken1,
reserveToken2
);
uint256[] memory reserveAmounts = converter.removeLiquidity(poolAmount, reserveTokens, minReturns);
_burnNetworkTokens(poolAnchor, reserveAmounts[0]);
if (reserveTokens[1].isNativeToken()) {
_vaultV3.sendValue(reserveAmounts[1]);
} else {
reserveTokens[1].safeTransfer(_vaultV3, reserveAmounts[1]);
}
}
}
function _poolTokensToMigrate(
IDSToken poolToken,
ILiquidityPoolConverter converter,
IReserveToken reserveToken
) private view returns (uint256) {
uint256 totalPositionsValue = totalPositionsValue(poolToken);
uint256 reserveBalance = converter.reserveBalance(reserveToken);
uint256 poolTokenSupply = poolToken.totalSupply();
uint256 positionsPoolTokenAmount = _mulDivF(poolTokenSupply, totalPositionsValue, reserveBalance);
uint256 protectedPoolTokenAmount = poolToken.balanceOf(address(_wallet));
if (positionsPoolTokenAmount >= protectedPoolTokenAmount) {
return 0;
}
uint256 poolAmountToMigrate = protectedPoolTokenAmount.sub(positionsPoolTokenAmount);
uint256 systemPoolAmount = _systemStore.systemBalance(poolToken);
return Math.min(poolAmountToMigrate, systemPoolAmount);
}
function _transferPosition(
address provider,
uint256 id,
address newProvider
) internal returns (uint256) {
Position memory removedPos = _removePosition(provider, id, PPM_RESOLUTION);
return
_addPosition(
newProvider,
removedPos.poolToken,
removedPos.reserveToken,
removedPos.poolAmount,
removedPos.reserveAmount,
removedPos.timestamp
);
}
function claimBalance(uint256 startIndex, uint256 endIndex) external nonReentrant {
(uint256[] memory amounts, uint256[] memory expirationTimes) = _store.lockedBalanceRange(
msg.sender,
startIndex,
endIndex
);
uint256 totalAmount = 0;
uint256 length = amounts.length;
assert(length == expirationTimes.length);
for (uint256 i = length; i > 0; i--) {
uint256 index = i - 1;
if (expirationTimes[index] > _time()) {
continue;
}
_store.removeLockedBalance(msg.sender, startIndex + index);
totalAmount = totalAmount.add(amounts[index]);
}
if (totalAmount > 0) {
_wallet.withdrawTokens(IReserveToken(address(_networkToken)), msg.sender, totalAmount);
}
}
function _addPosition(
address provider,
IDSToken poolToken,
IReserveToken reserveToken,
uint256 poolAmount,
uint256 reserveAmount,
uint256 timestamp
) internal returns (uint256) {
(Fraction memory spotRate, Fraction memory averageRate) = _reserveTokenRates(poolToken, reserveToken);
_verifyRateDeviation(spotRate.n, spotRate.d, averageRate.n, averageRate.d);
_stats.increaseTotalAmounts(provider, poolToken, reserveToken, poolAmount, reserveAmount);
_stats.addProviderPool(provider, poolToken);
return
_store.addProtectedLiquidity(
provider,
poolToken,
reserveToken,
poolAmount,
reserveAmount,
spotRate.n,
spotRate.d,
timestamp
);
}
function _removePosition(
address provider,
uint256 id,
uint32 portion
) private returns (Position memory) {
Position memory pos = _providerPosition(id, provider);
_poolWhitelisted(pos.poolToken);
require(pos.timestamp < _time(), "ERR_TOO_EARLY");
if (portion == PPM_RESOLUTION) {
_store.removeProtectedLiquidity(id);
} else {
uint256 fullPoolAmount = pos.poolAmount;
uint256 fullReserveAmount = pos.reserveAmount;
(pos.poolAmount, pos.reserveAmount) = _portionAmounts(pos.poolAmount, pos.reserveAmount, portion);
_store.updateProtectedLiquidityAmounts(
id,
fullPoolAmount - pos.poolAmount,
fullReserveAmount - pos.reserveAmount
);
}
_stats.decreaseTotalAmounts(pos.provider, pos.poolToken, pos.reserveToken, pos.poolAmount, pos.reserveAmount);
return pos;
}
function _lockTokens(address provider, uint256 amount) internal {
uint256 expirationTime = _time().add(_settings.lockDuration());
_store.addLockedBalance(provider, amount, expirationTime);
}
function _poolTokenRate(IDSToken poolToken, IReserveToken reserveToken)
internal
view
virtual
returns (Fraction memory)
{
uint256 poolTokenSupply = poolToken.totalSupply();
IConverter converter = IConverter(payable(_ownedBy(poolToken)));
uint256 reserveBalance = converter.getConnectorBalance(reserveToken);
return Fraction({ n: reserveBalance.mul(2), d: poolTokenSupply });
}
function _reserveTokenRates(IDSToken poolToken, IReserveToken reserveToken)
internal
view
returns (Fraction memory, Fraction memory)
{
ILiquidityPoolConverter converter = ILiquidityPoolConverter(payable(_ownedBy(poolToken)));
IReserveToken otherReserve = _converterOtherReserve(converter, reserveToken);
(uint256 spotRateN, uint256 spotRateD) = _converterReserveBalances(converter, otherReserve, reserveToken);
(uint256 averageRateN, uint256 averageRateD) = converter.recentAverageRate(reserveToken);
return (Fraction({ n: spotRateN, d: spotRateD }), Fraction({ n: averageRateN, d: averageRateD }));
}
function _packRates(
IDSToken poolToken,
IReserveToken reserveToken,
uint256 addSpotRateN,
uint256 addSpotRateD
) internal view returns (PackedRates memory) {
(Fraction memory removeSpotRate, Fraction memory removeAverageRate) = _reserveTokenRates(
poolToken,
reserveToken
);
assert((removeSpotRate.n | removeSpotRate.d | removeAverageRate.n | removeAverageRate.d) <= MAX_UINT128);
return _packRates(addSpotRateN, addSpotRateD, removeSpotRate, removeAverageRate);
}
function _packRates(
uint256 addSpotRateN,
uint256 addSpotRateD,
Fraction memory removeSpotRate,
Fraction memory removeAverageRate
) internal pure returns (PackedRates memory) {
assert((addSpotRateN | addSpotRateD) <= MAX_UINT128);
return
PackedRates({
addSpotRateN: uint128(addSpotRateN),
addSpotRateD: uint128(addSpotRateD),
removeSpotRateN: uint128(removeSpotRate.n),
removeSpotRateD: uint128(removeSpotRate.d),
removeAverageRateN: uint128(removeAverageRate.n),
removeAverageRateD: uint128(removeAverageRate.d)
});
}
function _verifyRateDeviation(
uint256 spotRateN,
uint256 spotRateD,
uint256 averageRateN,
uint256 averageRateD
) internal view {
uint256 ppmDelta = PPM_RESOLUTION - _settings.averageRateMaxDeviation();
uint256 min = spotRateN.mul(averageRateD).mul(ppmDelta).mul(ppmDelta);
uint256 mid = spotRateD.mul(averageRateN).mul(ppmDelta).mul(PPM_RESOLUTION);
uint256 max = spotRateN.mul(averageRateD).mul(PPM_RESOLUTION).mul(PPM_RESOLUTION);
require(min <= mid && mid <= max, "ERR_INVALID_RATE");
}
function _addLiquidity(
ILiquidityPoolConverter converter,
IReserveToken reserveToken1,
IReserveToken reserveToken2,
uint256 reserveAmount1,
uint256 reserveAmount2,
uint256 value
) internal {
IReserveToken[] memory reserveTokens = new IReserveToken[](2);
uint256[] memory amounts = new uint256[](2);
reserveTokens[0] = reserveToken1;
reserveTokens[1] = reserveToken2;
amounts[0] = reserveAmount1;
amounts[1] = reserveAmount2;
converter.addLiquidity{ value: value }(reserveTokens, amounts, 1);
}
function _removeLiquidity(
IDSToken poolToken,
uint256 poolAmount,
IReserveToken reserveToken1,
IReserveToken reserveToken2
) internal {
ILiquidityPoolConverter converter = ILiquidityPoolConverter(payable(_ownedBy(poolToken)));
(IReserveToken[] memory reserveTokens, uint256[] memory minReturns) = _removeLiquidityInput(
reserveToken1,
reserveToken2
);
converter.removeLiquidity(poolAmount, reserveTokens, minReturns);
}
function _position(uint256 id) internal view returns (Position memory) {
Position memory pos;
(
pos.provider,
pos.poolToken,
pos.reserveToken,
pos.poolAmount,
pos.reserveAmount,
pos.reserveRateN,
pos.reserveRateD,
pos.timestamp
) = _store.protectedLiquidity(id);
return pos;
}
function _providerPosition(uint256 id, address provider) internal view returns (Position memory) {
Position memory pos = _position(id);
require(pos.provider == provider, "ERR_ACCESS_DENIED");
return pos;
}
function _protectedAmountPlusFee(
uint256 poolAmount,
Fraction memory poolRate,
Fraction memory addRate,
Fraction memory removeRate
) internal pure returns (uint256) {
uint256 n = MathEx.ceilSqrt(addRate.d.mul(removeRate.n)).mul(poolRate.n);
uint256 d = MathEx.floorSqrt(addRate.n.mul(removeRate.d)).mul(poolRate.d);
uint256 x = n * poolAmount;
if (x / n == poolAmount) {
return x / d;
}
(uint256 hi, uint256 lo) = n > poolAmount ? (n, poolAmount) : (poolAmount, n);
(uint256 p, uint256 q) = MathEx.reducedRatio(hi, d, MAX_UINT256 / lo);
uint256 min = (hi / d).mul(lo);
if (q > 0) {
return Math.max(min, (p * lo) / q);
}
return min;
}
function _impLoss(Fraction memory prevRate, Fraction memory newRate) internal pure returns (Fraction memory) {
uint256 ratioN = newRate.n.mul(prevRate.d);
uint256 ratioD = newRate.d.mul(prevRate.n);
uint256 prod = ratioN * ratioD;
uint256 root = prod / ratioN == ratioD
? MathEx.floorSqrt(prod)
: MathEx.floorSqrt(ratioN) * MathEx.floorSqrt(ratioD);
uint256 sum = ratioN.add(ratioD);
if (sum % 2 == 0) {
sum /= 2;
return Fraction({ n: sum - root, d: sum });
}
return Fraction({ n: sum - root * 2, d: sum });
}
function _deductIL(uint256 value, Fraction memory loss) internal pure returns (uint256) {
uint256 maxVal = Math.max(1, value);
(uint256 lossN, uint256 lossD) = MathEx.reducedRatio(loss.n, loss.d, MAX_UINT256 / maxVal);
return value.mul(lossD.sub(lossN)).div(lossD);
}
function _mintNetworkTokens(
address owner,
IConverterAnchor poolAnchor,
uint256 amount
) private {
_systemStore.incNetworkTokensMinted(poolAnchor, amount);
_networkTokenGovernance.mint(owner, amount);
}
function _burnNetworkTokens(IConverterAnchor poolAnchor, uint256 amount) private {
_systemStore.decNetworkTokensMinted(poolAnchor, amount);
_networkTokenGovernance.burn(amount);
}
function _converterReserveBalances(
IConverter converter,
IReserveToken reserveToken1,
IReserveToken reserveToken2
) private view returns (uint256, uint256) {
return (converter.getConnectorBalance(reserveToken1), converter.getConnectorBalance(reserveToken2));
}
function _converterOtherReserve(IConverter converter, IReserveToken thisReserve)
private
view
returns (IReserveToken)
{
IReserveToken otherReserve = converter.connectorTokens(0);
return otherReserve != thisReserve ? otherReserve : converter.connectorTokens(1);
}
function _ownedBy(IOwned owned) private view returns (address) {
return owned.owner();
}
function _isNetworkToken(IReserveToken reserveToken) private view returns (bool) {
return address(reserveToken) == address(_networkToken);
}
function _removeLiquidityInput(IReserveToken reserveToken1, IReserveToken reserveToken2)
private
pure
returns (IReserveToken[] memory, uint256[] memory)
{
IReserveToken[] memory reserveTokens = new IReserveToken[](2);
uint256[] memory minReturns = new uint256[](2);
reserveTokens[0] = reserveToken1;
reserveTokens[1] = reserveToken2;
minReturns[0] = 1;
minReturns[1] = 1;
return (reserveTokens, minReturns);
}
function _portionAmounts(
uint256 poolAmount,
uint256 reserveAmount,
uint256 portion
) private pure returns (uint256, uint256) {
return (_mulDivF(poolAmount, portion, PPM_RESOLUTION), _mulDivF(reserveAmount, portion, PPM_RESOLUTION));
}
function _networkTokenMintingLimit(IConverterAnchor poolAnchor) private view returns (uint256) {
uint256 mintingLimit = _settings.networkTokenMintingLimits(poolAnchor);
return mintingLimit > 0 ? mintingLimit : _settings.defaultNetworkTokenMintingLimit();
}
function _liquidationAmount(
uint256 targetAmount,
Fraction memory poolRate,
IDSToken poolToken
) private view returns (uint256) {
uint256 poolAmount = _mulDivF(targetAmount, poolRate.d.mul(2), poolRate.n);
return Math.min(poolAmount, poolToken.balanceOf(address(_wallet)));
}
function _withdrawPoolTokens(IDSToken poolToken, uint256 poolAmount) private {
uint256 systemBalance = _systemStore.systemBalance(poolToken);
_systemStore.decSystemBalance(poolToken, Math.min(poolAmount, systemBalance));
_wallet.withdrawTokens(IReserveToken(address(poolToken)), address(this), poolAmount);
}
function _mulDivF(
uint256 x,
uint256 y,
uint256 z
) private pure returns (uint256) {
return x.mul(y).div(z);
}
function enableDepositing(bool state) external ownerOnly {
_addingEnabled = state;
}
function enableRemoving(bool state) external ownerOnly {
_removingEnabled = state;
}
function setTotalPositionsValue(IConverterAnchor poolAnchor, uint256 amount)
public
ownerOnly
poolSupportedAndWhitelisted(poolAnchor)
{
_totalPositionsValue[poolAnchor] = amount;
}
function setTotalPositionsValueMultiple(IConverterAnchor[] calldata poolAnchors, uint256[] calldata amounts)
public
ownerOnly
{
require(poolAnchors.length == amounts.length, "ERR_LENGTH_MISMATCH");
for (uint256 i = 0; i < poolAnchors.length; i++) {
setTotalPositionsValue(poolAnchors[i], amounts[i]);
}
}
function totalPositionsValue(IConverterAnchor poolAnchor) public view returns (uint256 amount) {
return _totalPositionsValue[poolAnchor];
}
}
文件 21 的 31: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);
}
}
文件 22 的 31:MathEx.sol
pragma solidity 0.6.12;
library MathEx {
uint256 private constant MAX_EXP_BIT_LEN = 4;
uint256 private constant MAX_EXP = 2**MAX_EXP_BIT_LEN - 1;
uint256 private constant MAX_UINT256 = uint256(-1);
function floorSqrt(uint256 num) internal pure returns (uint256) {
uint256 x = num / 2 + 1;
uint256 y = (x + num / x) / 2;
while (x > y) {
x = y;
y = (x + num / x) / 2;
}
return x;
}
function ceilSqrt(uint256 num) internal pure returns (uint256) {
uint256 x = floorSqrt(num);
return x * x == num ? x : x + 1;
}
function productRatio(
uint256 xn,
uint256 yn,
uint256 xd,
uint256 yd
) internal pure returns (uint256, uint256) {
uint256 n = mulDivC(xn, yn, MAX_UINT256);
uint256 d = mulDivC(xd, yd, MAX_UINT256);
uint256 z = n > d ? n : d;
if (z > 1) {
return (mulDivC(xn, yn, z), mulDivC(xd, yd, z));
}
return (xn * yn, xd * yd);
}
function reducedRatio(
uint256 n,
uint256 d,
uint256 max
) internal pure returns (uint256, uint256) {
(uint256 newN, uint256 newD) = (n, d);
if (newN > max || newD > max) {
(newN, newD) = normalizedRatio(newN, newD, max);
}
if (newN != newD) {
return (newN, newD);
}
return (1, 1);
}
function normalizedRatio(
uint256 a,
uint256 b,
uint256 scale
) internal pure returns (uint256, uint256) {
if (a <= b) {
return accurateRatio(a, b, scale);
}
(uint256 y, uint256 x) = accurateRatio(b, a, scale);
return (x, y);
}
function accurateRatio(
uint256 a,
uint256 b,
uint256 scale
) internal pure returns (uint256, uint256) {
uint256 maxVal = MAX_UINT256 / scale;
if (a > maxVal) {
uint256 c = a / (maxVal + 1) + 1;
a /= c;
b /= c;
}
if (a != b) {
uint256 newN = a * scale;
uint256 newD = unsafeAdd(a, b);
if (newD >= a) {
uint256 x = roundDiv(newN, newD);
uint256 y = scale - x;
return (x, y);
}
if (newN < b - (b - a) / 2) {
return (0, scale);
}
return (1, scale - 1);
}
return (scale / 2, scale / 2);
}
function roundDiv(uint256 n, uint256 d) internal pure returns (uint256) {
return n / d + (n % d) / (d - d / 2);
}
function geometricMean(uint256[] memory values) internal pure returns (uint256) {
uint256 numOfDigits = 0;
uint256 length = values.length;
for (uint256 i = 0; i < length; ++i) {
numOfDigits += decimalLength(values[i]);
}
return uint256(10)**(roundDivUnsafe(numOfDigits, length) - 1);
}
function decimalLength(uint256 x) internal pure returns (uint256) {
uint256 y = 0;
for (uint256 tmpX = x; tmpX > 0; tmpX /= 10) {
++y;
}
return y;
}
function roundDivUnsafe(uint256 n, uint256 d) internal pure returns (uint256) {
return (n + d / 2) / d;
}
function mulDivF(
uint256 x,
uint256 y,
uint256 z
) internal pure returns (uint256) {
(uint256 xyh, uint256 xyl) = mul512(x, y);
if (xyh == 0) {
return xyl / z;
}
require(xyh < z, "ERR_OVERFLOW");
uint256 m = mulMod(x, y, z);
(uint256 nh, uint256 nl) = sub512(xyh, xyl, m);
if (nh == 0) {
return nl / z;
}
uint256 p = unsafeSub(0, z) & z;
uint256 q = div512(nh, nl, p);
uint256 r = inv256(z / p);
return unsafeMul(q, r);
}
function mulDivC(
uint256 x,
uint256 y,
uint256 z
) internal pure returns (uint256) {
uint256 w = mulDivF(x, y, z);
if (mulMod(x, y, z) > 0) {
require(w < MAX_UINT256, "ERR_OVERFLOW");
return w + 1;
}
return w;
}
function mul512(uint256 x, uint256 y) private pure returns (uint256, uint256) {
uint256 p = mulModMax(x, y);
uint256 q = unsafeMul(x, y);
if (p >= q) {
return (p - q, q);
}
return (unsafeSub(p, q) - 1, q);
}
function sub512(
uint256 xh,
uint256 xl,
uint256 y
) private pure returns (uint256, uint256) {
if (xl >= y) {
return (xh, xl - y);
}
return (xh - 1, unsafeSub(xl, y));
}
function div512(
uint256 xh,
uint256 xl,
uint256 pow2n
) private pure returns (uint256) {
uint256 pow2nInv = unsafeAdd(unsafeSub(0, pow2n) / pow2n, 1);
return unsafeMul(xh, pow2nInv) | (xl / pow2n);
}
function inv256(uint256 d) private pure returns (uint256) {
uint256 x = 1;
for (uint256 i = 0; i < 8; ++i) {
x = unsafeMul(x, unsafeSub(2, unsafeMul(x, d)));
}
return x;
}
function unsafeAdd(uint256 x, uint256 y) private pure returns (uint256) {
return x + y;
}
function unsafeSub(uint256 x, uint256 y) private pure returns (uint256) {
return x - y;
}
function unsafeMul(uint256 x, uint256 y) private pure returns (uint256) {
return x * y;
}
function mulModMax(uint256 x, uint256 y) private pure returns (uint256) {
return mulmod(x, y, MAX_UINT256);
}
function mulMod(
uint256 x,
uint256 y,
uint256 z
) private pure returns (uint256) {
return mulmod(x, y, z);
}
}
文件 23 的 31: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;
}
}
文件 24 的 31:ReentrancyGuard.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () internal {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 25 的 31: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));
}
}
文件 26 的 31: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");
}
}
}
文件 27 的 31: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);
}
}
文件 28 的 31: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;
}
}
文件 29 的 31:Time.sol
pragma solidity 0.6.12;
contract Time {
function _time() internal view virtual returns (uint256) {
return block.timestamp;
}
}
文件 30 的 31:Types.sol
pragma solidity 0.6.12;
struct Fraction {
uint256 n;
uint256 d;
}
文件 31 的 31: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/liquidity-protection/LiquidityProtection.sol": "LiquidityProtection"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address payable","name":"vaultV3","type":"address"},{"internalType":"contract ILiquidityProtectionSettings","name":"settings","type":"address"},{"internalType":"contract ILiquidityProtectionStore","name":"store","type":"address"},{"internalType":"contract ILiquidityProtectionStats","name":"stats","type":"address"},{"internalType":"contract ILiquidityProtectionSystemStore","name":"systemStore","type":"address"},{"internalType":"contract ITokenHolder","name":"wallet","type":"address"},{"internalType":"contract ITokenGovernance","name":"networkTokenGovernance","type":"address"},{"internalType":"contract ITokenGovernance","name":"govTokenGovernance","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"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptStoreOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptWalletOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConverterAnchor","name":"poolAnchor","type":"address"},{"internalType":"contract IReserveToken","name":"reserveToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"contract IConverterAnchor","name":"poolAnchor","type":"address"},{"internalType":"contract IReserveToken","name":"reserveToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addLiquidityFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"endIndex","type":"uint256"}],"name":"claimBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"enableDepositing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"enableRemoving","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConverterAnchor[]","name":"poolAnchors","type":"address[]"}],"name":"migrateSystemPoolTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"newOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IConverterAnchor","name":"poolAnchor","type":"address"}],"name":"poolAvailableSpace","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IDSToken","name":"poolToken","type":"address"}],"name":"poolDeficitPPM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"positionValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint32","name":"portion","type":"uint32"}],"name":"removeLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint32","name":"portion","type":"uint32"},{"internalType":"uint256","name":"removeTimestamp","type":"uint256"}],"name":"removeLiquidityReturn","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IConverterAnchor","name":"poolAnchor","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setTotalPositionsValue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IConverterAnchor[]","name":"poolAnchors","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"setTotalPositionsValueMultiple","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settings","outputs":[{"internalType":"contract ILiquidityProtectionSettings","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stats","outputs":[{"internalType":"contract ILiquidityProtectionStats","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"store","outputs":[{"internalType":"contract ILiquidityProtectionStore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IConverterAnchor","name":"poolAnchor","type":"address"}],"name":"totalPositionsValue","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"newProvider","type":"address"}],"name":"transferPosition","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"newProvider","type":"address"},{"internalType":"contract ITransferPositionCallback","name":"callback","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"transferPositionAndNotify","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferStoreOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferWalletOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]