Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
LnCollateralSystem
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-12-23 */ /** *Submitted for verification at Etherscan.io on 2020-12-21 */ // SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity >=0.4.24 <0.8.0; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function _isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; // solhint-disable-next-line no-inline-assembly assembly { cs := extcodesize(self) } return cs == 0; } } /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ 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"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ 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"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{value: value}(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(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 { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } interface IERC20 { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function transfer(address to, uint value) external returns (bool); function approve(address spender, uint value) external returns (bool); function transferFrom( address from, address to, uint value ) external returns (bool); event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); } // a facade for prices fetch from oracles interface LnPrices { // get price for a currency function getPrice(bytes32 currencyName) external view returns (uint); // get price and updated time for a currency function getPriceAndUpdatedTime(bytes32 currencyName) external view returns (uint price, uint time); // is the price is stale function isStale(bytes32 currencyName) external view returns (bool); // the defined stale time function stalePeriod() external view returns (uint); // exchange amount of source currenty for some dest currency, also get source and dest curreny price function exchange( bytes32 sourceName, uint sourceAmount, bytes32 destName ) external view returns (uint); // exchange amount of source currenty for some dest currency function exchangeAndPrices( bytes32 sourceName, uint sourceAmount, bytes32 destName ) external view returns ( uint value, uint sourcePrice, uint destPrice ); // price names function LUSD() external view returns (bytes32); function LINA() external view returns (bytes32); } abstract contract LnBasePrices is LnPrices { // const name bytes32 public constant override LINA = "LINA"; bytes32 public constant override LUSD = "lUSD"; } /** * @title LnAdminUpgradeable * * @dev This is an upgradeable version of `LnAdmin` by replacing the constructor with * an initializer and reserving storage slots. */ contract LnAdminUpgradeable is Initializable { event CandidateChanged(address oldCandidate, address newCandidate); event AdminChanged(address oldAdmin, address newAdmin); address public admin; address public candidate; function __LnAdminUpgradeable_init(address _admin) public initializer { require(_admin != address(0), "LnAdminUpgradeable: zero address"); admin = _admin; emit AdminChanged(address(0), _admin); } function setCandidate(address _candidate) external onlyAdmin { address old = candidate; candidate = _candidate; emit CandidateChanged(old, candidate); } function becomeAdmin() external { require(msg.sender == candidate, "LnAdminUpgradeable: only candidate can become admin"); address old = admin; admin = candidate; emit AdminChanged(old, admin); } modifier onlyAdmin { require((msg.sender == admin), "LnAdminUpgradeable: only the contract admin can perform this action"); _; } // Reserved storage space to allow for layout changes in the future. uint256[48] private __gap; } // Reward Distributor contract LnRewardLocker is LnAdminUpgradeable { using SafeMath for uint256; struct RewardData { uint64 lockToTime; uint256 amount; } mapping(address => RewardData[]) public userRewards; // RewardData[0] is claimable mapping(address => uint256) public balanceOf; uint256 public totalNeedToReward; uint256 public constant maxRewardArrayLen = 100; address feeSysAddr; IERC20 public linaToken; function __LnRewardLocker_init(address _admin, address linaAddress) public initializer { __LnAdminUpgradeable_init(_admin); linaToken = IERC20(linaAddress); } function setLinaAddress(address _token) external onlyAdmin { linaToken = IERC20(_token); } function Init(address _feeSysAddr) external onlyAdmin { feeSysAddr = _feeSysAddr; } modifier onlyFeeSys() { require((msg.sender == feeSysAddr), "Only Fee System call"); _; } function appendReward( address _user, uint256 _amount, uint64 _lockTo ) external onlyFeeSys { if (userRewards[_user].length >= maxRewardArrayLen) { Slimming(_user); } require(userRewards[_user].length <= maxRewardArrayLen, "user array out of"); // init cliamable if (userRewards[_user].length == 0) { RewardData memory data = RewardData({lockToTime: 0, amount: 0}); userRewards[_user].push(data); } // append new reward RewardData memory data = RewardData({lockToTime: _lockTo, amount: _amount}); userRewards[_user].push(data); balanceOf[_user] = balanceOf[_user].add(_amount); totalNeedToReward = totalNeedToReward.add(_amount); emit AppendReward(_user, _amount, _lockTo); } // move claimable to RewardData[0] function Slimming(address _user) public { require(userRewards[_user].length > 1, "not data to slimming"); RewardData storage claimable = userRewards[_user][0]; for (uint256 i = 1; i < userRewards[_user].length; ) { if (now >= userRewards[_user][i].lockToTime) { claimable.amount = claimable.amount.add(userRewards[_user][i].amount); //swap last to current position uint256 len = userRewards[_user].length; userRewards[_user][i].lockToTime = userRewards[_user][len - 1].lockToTime; userRewards[_user][i].amount = userRewards[_user][len - 1].amount; userRewards[_user].pop(); // delete last one } else { i++; } } } // if lock lina is collateral, claimable need calc to fix target ratio function ClaimMaxable() public { address user = msg.sender; Slimming(user); _claim(user, userRewards[user][0].amount); } function _claim(address _user, uint256 _amount) internal { userRewards[_user][0].amount = userRewards[_user][0].amount.sub(_amount); balanceOf[_user] = balanceOf[_user].sub(_amount); totalNeedToReward = totalNeedToReward.sub(_amount); linaToken.transfer(_user, _amount); emit ClaimLog(_user, _amount); } function Claim(uint256 _amount) public { address user = msg.sender; Slimming(user); require(_amount <= userRewards[user][0].amount, "Claim amount invalid"); _claim(user, _amount); } event AppendReward(address user, uint256 amount, uint64 lockTo); event ClaimLog(address user, uint256 amount); // Reserved storage space to allow for layout changes in the future. uint256[45] private __gap; } interface IAsset { function keyName() external view returns (bytes32); } contract LnAdmin { address public admin; address public candidate; constructor(address _admin) public { require(_admin != address(0), "admin address cannot be 0"); admin = _admin; emit AdminChanged(address(0), _admin); } function setCandidate(address _candidate) external onlyAdmin { address old = candidate; candidate = _candidate; emit CandidateChanged(old, candidate); } function becomeAdmin() external { require(msg.sender == candidate, "Only candidate can become admin"); address old = admin; admin = candidate; emit AdminChanged(old, admin); } modifier onlyAdmin { require((msg.sender == admin), "Only the contract admin can perform this action"); _; } event CandidateChanged(address oldCandidate, address newCandidate); event AdminChanged(address oldAdmin, address newAdmin); } contract LnConfig is LnAdmin { mapping(bytes32 => uint) internal mUintConfig; constructor(address _admin) public LnAdmin(_admin) {} //some configue keys bytes32 public constant BUILD_RATIO = "BuildRatio"; // percent, base 10e18 function getUint(bytes32 key) external view returns (uint) { return mUintConfig[key]; } function setUint(bytes32 key, uint value) external onlyAdmin { mUintConfig[key] = value; emit SetUintConfig(key, value); } function deleteUint(bytes32 key) external onlyAdmin { delete mUintConfig[key]; emit SetUintConfig(key, 0); } function batchSet(bytes32[] calldata names, uint[] calldata values) external onlyAdmin { require(names.length == values.length, "Input lengths must match"); for (uint i = 0; i < names.length; i++) { mUintConfig[names[i]] = values[i]; emit SetUintConfig(names[i], values[i]); } } event SetUintConfig(bytes32 key, uint value); } library SafeDecimalMath { using SafeMath for uint; uint8 public constant decimals = 18; uint8 public constant highPrecisionDecimals = 27; uint public constant UNIT = 10**uint(decimals); uint public constant PRECISE_UNIT = 10**uint(highPrecisionDecimals); uint private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint(highPrecisionDecimals - decimals); function unit() external pure returns (uint) { return UNIT; } function preciseUnit() external pure returns (uint) { return PRECISE_UNIT; } function multiplyDecimal(uint x, uint y) internal pure returns (uint) { return x.mul(y) / UNIT; } function _multiplyDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { uint quotientTimesTen = x.mul(y) / (precisionUnit / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } function multiplyDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, PRECISE_UNIT); } function multiplyDecimalRound(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, UNIT); } function divideDecimal(uint x, uint y) internal pure returns (uint) { return x.mul(UNIT).div(y); } function _divideDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { uint resultTimesTen = x.mul(precisionUnit * 10).div(y); if (resultTimesTen % 10 >= 5) { resultTimesTen += 10; } return resultTimesTen / 10; } function divideDecimalRound(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, UNIT); } function divideDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, PRECISE_UNIT); } function decimalToPreciseDecimal(uint i) internal pure returns (uint) { return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR); } function preciseDecimalToDecimal(uint i) internal pure returns (uint) { uint quotientTimesTen = i / (UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } } /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer {} function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } uint256[50] private __gap; } /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal initializer { __Context_init_unchained(); __Pausable_init_unchained(); } function __Pausable_init_unchained() internal initializer { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!_paused, "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(_paused, "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } uint256[49] private __gap; } /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ 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"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ 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"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{value: value}(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(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 { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } contract LnAddressStorage is LnAdmin { mapping(bytes32 => address) public mAddrs; constructor(address _admin) public LnAdmin(_admin) {} function updateAll(bytes32[] calldata names, address[] calldata destinations) external onlyAdmin { require(names.length == destinations.length, "Input lengths must match"); for (uint i = 0; i < names.length; i++) { mAddrs[names[i]] = destinations[i]; emit StorageAddressUpdated(names[i], destinations[i]); } } function update(bytes32 name, address dest) external onlyAdmin { require(name != "", "name can not be empty"); require(dest != address(0), "address cannot be 0"); mAddrs[name] = dest; emit StorageAddressUpdated(name, dest); } function getAddress(bytes32 name) external view returns (address) { return mAddrs[name]; } function getAddressWithRequire(bytes32 name, string calldata reason) external view returns (address) { address _foundAddress = mAddrs[name]; require(_foundAddress != address(0), reason); return _foundAddress; } event StorageAddressUpdated(bytes32 name, address addr); } interface LnAddressCache { function updateAddressCache(LnAddressStorage _addressStorage) external; event CachedAddressUpdated(bytes32 name, address addr); } contract testAddressCache is LnAddressCache, LnAdmin { address public addr1; address public addr2; constructor(address _admin) public LnAdmin(_admin) {} function updateAddressCache(LnAddressStorage _addressStorage) public override onlyAdmin { addr1 = LnAddressStorage(_addressStorage).getAddressWithRequire("a", ""); addr2 = LnAddressStorage(_addressStorage).getAddressWithRequire("b", ""); emit CachedAddressUpdated("a", addr1); emit CachedAddressUpdated("b", addr2); } } /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {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]; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(value))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(value))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(value))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint256(_at(set._inner, index))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } } /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } /** * @dev Contract module that allows children to implement role-based access * control mechanisms. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ 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; /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view returns (bool) { return _roles[role].members.contains(account); } /** * @dev Returns the number of accounts that have `role`. Can be used * together with {getRoleMember} to enumerate all bearers of a role. */ function getRoleMemberCount(bytes32 role) public view returns (uint256) { return _roles[role].members.length(); } /** * @dev Returns one of the accounts that have `role`. `index` must be a * value between 0 and {getRoleMemberCount}, non-inclusive. * * Role bearers are not sorted in any particular way, and their ordering may * change at any point. * * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure * you perform all queries on the same block. See the following * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] * for more information. */ function getRoleMember(bytes32 role, uint256 index) public view returns (address) { return _roles[role].members.at(index); } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ 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); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ 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); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) public virtual { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ 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()); } } } // example: //LnAccessControl accessCtrl = LnAccessControl(addressStorage.getAddress("LnAccessControl")); //require(accessCtrl.hasRole(accessCtrl.DEBT_SYSTEM(), _address), "Need debt system access role"); // contract access control contract LnAccessControl is AccessControl { using Address for address; // ------------------------------------------------------- // role type bytes32 public constant ISSUE_ASSET_ROLE = ("ISSUE_ASSET"); //keccak256 bytes32 public constant BURN_ASSET_ROLE = ("BURN_ASSET"); bytes32 public constant DEBT_SYSTEM = ("LnDebtSystem"); // ------------------------------------------------------- constructor(address admin) public { _setupRole(DEFAULT_ADMIN_ROLE, admin); } function IsAdmin(address _address) public view returns (bool) { return hasRole(DEFAULT_ADMIN_ROLE, _address); } function SetAdmin(address _address) public returns (bool) { require(IsAdmin(msg.sender), "Only admin"); _setupRole(DEFAULT_ADMIN_ROLE, _address); } // ------------------------------------------------------- // this func need admin role. grantRole and revokeRole need admin role function SetRoles( bytes32 roleType, address[] calldata addresses, bool[] calldata setTo ) external { require(IsAdmin(msg.sender), "Only admin"); _setRoles(roleType, addresses, setTo); } function _setRoles( bytes32 roleType, address[] calldata addresses, bool[] calldata setTo ) private { require(addresses.length == setTo.length, "parameter address length not eq"); for (uint256 i = 0; i < addresses.length; i++) { //require(addresses[i].isContract(), "Role address need contract only"); if (setTo[i]) { grantRole(roleType, addresses[i]); } else { revokeRole(roleType, addresses[i]); } } } // function SetRoles(bytes32 roleType, address[] calldata addresses, bool[] calldata setTo) public { // _setRoles(roleType, addresses, setTo); // } // Issue burn function SetIssueAssetRole(address[] calldata issuer, bool[] calldata setTo) public { _setRoles(ISSUE_ASSET_ROLE, issuer, setTo); } function SetBurnAssetRole(address[] calldata burner, bool[] calldata setTo) public { _setRoles(BURN_ASSET_ROLE, burner, setTo); } // function SetDebtSystemRole(address[] calldata _address, bool[] calldata _setTo) public { _setRoles(DEBT_SYSTEM, _address, _setTo); } } /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMathUpgradeable { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable { using SafeMathUpgradeable for uint256; mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal initializer { __Context_init_unchained(); __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal initializer { _name = name_; _symbol = symbol_; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve( sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance") ); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve( _msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero") ); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} uint256[44] private __gap; } /** * @title LnAssetUpgradeable * * @dev This is an upgradeable version of `LnAsset`. */ contract LnAssetUpgradeable is ERC20Upgradeable, LnAdminUpgradeable, IAsset, LnAddressCache { bytes32 mKeyName; LnAccessControl accessCtrl; modifier onlyIssueAssetRole(address _address) { require(accessCtrl.hasRole(accessCtrl.ISSUE_ASSET_ROLE(), _address), "Need issue access role"); _; } modifier onlyBurnAssetRole(address _address) { require(accessCtrl.hasRole(accessCtrl.BURN_ASSET_ROLE(), _address), "Need burn access role"); _; } function __LnAssetUpgradeable_init( bytes32 _key, string memory _name, string memory _symbol, address _admin ) public initializer { __ERC20_init(_name, _symbol); __LnAdminUpgradeable_init(_admin); mKeyName = _key; } function keyName() external view override returns (bytes32) { return mKeyName; } function updateAddressCache(LnAddressStorage _addressStorage) public override onlyAdmin { accessCtrl = LnAccessControl( _addressStorage.getAddressWithRequire("LnAccessControl", "LnAccessControl address not valid") ); emit CachedAddressUpdated("LnAccessControl", address(accessCtrl)); } function mint(address account, uint256 amount) external onlyIssueAssetRole(msg.sender) { _mint(account, amount); } function burn(address account, uint amount) external onlyBurnAssetRole(msg.sender) { _burn(account, amount); } // Reserved storage space to allow for layout changes in the future. uint256[48] private __gap; } contract LnAssetSystem is LnAddressStorage { using SafeMath for uint; using SafeDecimalMath for uint; IAsset[] public mAssetList; // 合约地址数组 mapping(address => bytes32) public mAddress2Names; // 地址到名称的映射 constructor(address _admin) public LnAddressStorage(_admin) {} function addAsset(IAsset asset) external onlyAdmin { bytes32 name = asset.keyName(); require(mAddrs[name] == address(0), "Asset already exists"); require(mAddress2Names[address(asset)] == bytes32(0), "Asset address already exists"); mAssetList.push(asset); mAddrs[name] = address(asset); mAddress2Names[address(asset)] = name; emit AssetAdded(name, address(asset)); } function removeAsset(bytes32 name) external onlyAdmin { address assetToRemove = address(mAddrs[name]); require(assetToRemove != address(0), "asset does not exist"); // Remove from list for (uint i = 0; i < mAssetList.length; i++) { if (address(mAssetList[i]) == assetToRemove) { delete mAssetList[i]; mAssetList[i] = mAssetList[mAssetList.length - 1]; mAssetList.pop(); break; } } // And remove it from the assets mapping delete mAddress2Names[assetToRemove]; delete mAddrs[name]; emit AssetRemoved(name, assetToRemove); } function assetNumber() external view returns (uint) { return mAssetList.length; } // check exchange rate invalid condition ? invalid just fail. function totalAssetsInUsd() public view returns (uint256 rTotal) { require(mAddrs["LnPrices"] != address(0), "LnPrices address cannot access"); LnPrices priceGetter = LnPrices(mAddrs["LnPrices"]); //getAddress for (uint256 i = 0; i < mAssetList.length; i++) { uint256 exchangeRate = priceGetter.getPrice(mAssetList[i].keyName()); rTotal = rTotal.add(LnAssetUpgradeable(address(mAssetList[i])).totalSupply().multiplyDecimal(exchangeRate)); } } function getAssetAddresses() external view returns (address[] memory) { address[] memory addr = new address[](mAssetList.length); for (uint256 i = 0; i < mAssetList.length; i++) { addr[i] = address(mAssetList[i]); } return addr; } event AssetAdded(bytes32 name, address asset); event AssetRemoved(bytes32 name, address asset); } contract LnFeeSystem is LnAdminUpgradeable, LnAddressCache { using SafeMath for uint256; using SafeDecimalMath for uint256; address public constant FEE_DUMMY_ADDRESS = address(0x2048); struct UserDebtData { uint256 PeriodID; // Period id uint256 debtProportion; uint256 debtFactor; // PRECISE_UNIT } struct RewardPeriod { uint256 id; // Period id uint256 startingDebtFactor; uint256 startTime; uint256 feesToDistribute; // 要分配的费用 uint256 feesClaimed; // 已领取的费用 uint256 rewardsToDistribute; // 要分配的奖励 uint256 rewardsClaimed; // 已领取的奖励 } RewardPeriod public curRewardPeriod; RewardPeriod public preRewardPeriod; uint256 public OnePeriodSecs; uint64 public LockTime; mapping(address => uint256) public userLastClaimedId; mapping(address => UserDebtData[2]) public userPeriodDebt; // one for current period, one for pre period // LnDebtSystem public debtSystem; LnCollateralSystem public collateralSystem; LnRewardLocker public rewardLocker; LnAssetSystem mAssets; address public exchangeSystemAddress; address public rewardDistributer; function __LnFeeSystem_init(address _admin) public initializer { __LnAdminUpgradeable_init(_admin); OnePeriodSecs = 1 weeks; LockTime = uint64(52 weeks); } // Note: before start run need call this func to init. function Init(address _exchangeSystem, address _rewardDistri) public onlyAdmin { exchangeSystemAddress = _exchangeSystem; rewardDistributer = _rewardDistri; } //set period data, maybe copy from old contract function SetPeriodData( int16 index, // 0 current 1 pre uint256 id, uint256 startingDebtFactor, uint256 startTime, uint256 feesToDistribute, uint256 feesClaimed, uint256 rewardsToDistribute, uint256 rewardsClaimed ) public onlyAdmin { RewardPeriod storage toset = index == 0 ? curRewardPeriod : preRewardPeriod; toset.id = id; toset.startingDebtFactor = startingDebtFactor; toset.startTime = startTime; toset.feesToDistribute = feesToDistribute; toset.feesClaimed = feesClaimed; toset.rewardsToDistribute = rewardsToDistribute; toset.rewardsClaimed = rewardsClaimed; } function setExchangeSystemAddress(address _address) public onlyAdmin { exchangeSystemAddress = _address; } modifier onlyExchanger { require((msg.sender == exchangeSystemAddress), "Only Exchange System call"); _; } modifier onlyDistributer { require((msg.sender == rewardDistributer), "Only Reward Distributer call"); _; } function addExchangeFee(uint feeUsd) public onlyExchanger { curRewardPeriod.feesToDistribute = curRewardPeriod.feesToDistribute.add(feeUsd); emit ExchangeFee(feeUsd); } // TODO: call by contract or auto distribute? function addCollateralRewards(uint reward) public onlyDistributer { curRewardPeriod.rewardsToDistribute = curRewardPeriod.rewardsToDistribute.add(reward); emit RewardCollateral(reward); } event ExchangeFee(uint feeUsd); event RewardCollateral(uint reward); event FeesClaimed(address user, uint lUSDAmount, uint linaRewards); function updateAddressCache(LnAddressStorage _addressStorage) public override onlyAdmin { debtSystem = LnDebtSystem(_addressStorage.getAddressWithRequire("LnDebtSystem", "LnDebtSystem address not valid")); address payable collateralAddress = payable(_addressStorage.getAddressWithRequire("LnCollateralSystem", "LnCollateralSystem address not valid")); collateralSystem = LnCollateralSystem(collateralAddress); rewardLocker = LnRewardLocker( _addressStorage.getAddressWithRequire("LnRewardLocker", "LnRewardLocker address not valid") ); mAssets = LnAssetSystem(_addressStorage.getAddressWithRequire("LnAssetSystem", "LnAssetSystem address not valid")); // as Init func. record LnExchangeSystem address exchangeSystemAddress = _addressStorage.getAddressWithRequire( "LnExchangeSystem", "LnExchangeSystem address not valid" ); emit CachedAddressUpdated("LnDebtSystem", address(debtSystem)); emit CachedAddressUpdated("LnCollateralSystem", address(collateralSystem)); emit CachedAddressUpdated("LnRewardLocker", address(rewardLocker)); emit CachedAddressUpdated("LnAssetSystem", address(mAssets)); emit CachedAddressUpdated("LnExchangeSystem", address(exchangeSystemAddress)); } function switchPeriod() public { require(now >= curRewardPeriod.startTime + OnePeriodSecs, "It's not time to switch"); preRewardPeriod.id = curRewardPeriod.id; preRewardPeriod.startingDebtFactor = curRewardPeriod.startingDebtFactor; preRewardPeriod.startTime = curRewardPeriod.startTime; preRewardPeriod.feesToDistribute = curRewardPeriod.feesToDistribute.add( preRewardPeriod.feesToDistribute.sub(preRewardPeriod.feesClaimed) ); preRewardPeriod.feesClaimed = 0; preRewardPeriod.rewardsToDistribute = curRewardPeriod.rewardsToDistribute.add( preRewardPeriod.rewardsToDistribute.sub(preRewardPeriod.rewardsClaimed) ); preRewardPeriod.rewardsClaimed = 0; curRewardPeriod.id = curRewardPeriod.id + 1; curRewardPeriod.startingDebtFactor = debtSystem.LastSystemDebtFactor(); curRewardPeriod.startTime = now; curRewardPeriod.feesToDistribute = 0; curRewardPeriod.feesClaimed = 0; curRewardPeriod.rewardsToDistribute = 0; curRewardPeriod.rewardsClaimed = 0; } function feePeriodDuration() external view returns (uint) { return OnePeriodSecs; } function recentFeePeriods(uint index) external view returns ( uint256 id, uint256 startingDebtFactor, uint256 startTime, uint256 feesToDistribute, uint256 feesClaimed, uint256 rewardsToDistribute, uint256 rewardsClaimed ) { if (index > 1) { return (0, 0, 0, 0, 0, 0, 0); } RewardPeriod memory rewardPd; if (index == 0) { rewardPd = curRewardPeriod; } else { rewardPd = preRewardPeriod; } return ( rewardPd.id, rewardPd.startingDebtFactor, rewardPd.startTime, rewardPd.feesToDistribute, rewardPd.feesClaimed, rewardPd.rewardsToDistribute, rewardPd.rewardsClaimed ); } modifier onlyDebtSystem() { require(msg.sender == address(debtSystem), "Only Debt system call"); _; } // build record function RecordUserDebt( address user, uint256 debtProportion, uint256 debtFactor ) public onlyDebtSystem { uint256 curId = curRewardPeriod.id; uint256 minPos = 0; if (userPeriodDebt[user][0].PeriodID > userPeriodDebt[user][1].PeriodID) { minPos = 1; } uint256 pos = minPos; for (uint64 i = 0; i < userPeriodDebt[user].length; i++) { if (userPeriodDebt[user][i].PeriodID == curId) { pos = i; break; } } userPeriodDebt[user][pos].PeriodID = curId; userPeriodDebt[user][pos].debtProportion = debtProportion; userPeriodDebt[user][pos].debtFactor = debtFactor; } function isFeesClaimable(address account) public view returns (bool feesClaimable) { if (collateralSystem.IsSatisfyTargetRatio(account) == false) { return false; } if (userLastClaimedId[account] == preRewardPeriod.id) { return false; } // TODO: other condition? return true; } // total fee and total reward function feesAvailable(address user) public view returns (uint, uint) { if (preRewardPeriod.feesToDistribute == 0 && preRewardPeriod.rewardsToDistribute == 0) { return (0, 0); } uint256 debtFactor = 0; uint256 debtProportion = 0; uint256 pid = 0; //get last period factor for (uint64 i = 0; i < userPeriodDebt[user].length; i++) { if (userPeriodDebt[user][i].PeriodID < curRewardPeriod.id && userPeriodDebt[user][i].PeriodID > pid) { pid = curRewardPeriod.id; debtFactor = userPeriodDebt[user][i].debtFactor; debtProportion = userPeriodDebt[user][i].debtProportion; } } // //if (debtProportion == 0) { // (debtProportion, debtFactor) = debtSystem.userDebtState(user); //} if (debtProportion == 0) { return (0, 0); } uint256 lastPeriodDebtFactor = curRewardPeriod.startingDebtFactor; uint256 userDebtProportion = lastPeriodDebtFactor.divideDecimalRoundPrecise(debtFactor).multiplyDecimalRoundPrecise(debtProportion); uint256 fee = preRewardPeriod .feesToDistribute .decimalToPreciseDecimal() .multiplyDecimalRoundPrecise(userDebtProportion) .preciseDecimalToDecimal(); uint256 reward = preRewardPeriod .rewardsToDistribute .decimalToPreciseDecimal() .multiplyDecimalRoundPrecise(userDebtProportion) .preciseDecimalToDecimal(); return (fee, reward); } // claim fee and reward. function claimFees() external returns (bool) { address user = msg.sender; require(isFeesClaimable(user), "User is not claimable"); userLastClaimedId[user] = preRewardPeriod.id; // fee reward: mint lusd // : rewardLocker.appendReward(use, reward, now + 1 years); (uint256 fee, uint256 reward) = feesAvailable(user); require(fee > 0 || reward > 0, "Nothing to claim"); if (fee > 0) { LnAssetUpgradeable lusd = LnAssetUpgradeable(mAssets.getAddressWithRequire("lUSD", "get lUSD asset address fail")); lusd.burn(FEE_DUMMY_ADDRESS, fee); lusd.mint(user, fee); } if (reward > 0) { uint64 totime = uint64(now + LockTime); rewardLocker.appendReward(user, reward, totime); } emit FeesClaimed(user, fee, reward); return true; } // Reserved storage space to allow for layout changes in the future. uint256[38] private __gap; } contract LnFeeSystemTest is LnFeeSystem { function __LnFeeSystemTest_init(address _admin) public initializer { __LnFeeSystem_init(_admin); OnePeriodSecs = 6 hours; LockTime = 1 hours; } } contract LnDebtSystem is LnAdminUpgradeable, LnAddressCache { using SafeMath for uint; using SafeDecimalMath for uint; using Address for address; // ------------------------------------------------------- // need set before system running value. LnAccessControl private accessCtrl; LnAssetSystem private assetSys; LnFeeSystem public feeSystem; // ------------------------------------------------------- struct DebtData { uint256 debtProportion; uint256 debtFactor; // PRECISE_UNIT } mapping(address => DebtData) public userDebtState; //use mapping to store array data mapping(uint256 => uint256) public lastDebtFactors; // PRECISE_UNIT Note: 能直接记 factor 的记 factor, 不能记的就用index查 uint256 public debtCurrentIndex; // length of array. this index of array no value // follow var use to manage array size. uint256 public lastCloseAt; // close at array index uint256 public lastDeletTo; // delete to array index, lastDeletTo < lastCloseAt uint256 public constant MAX_DEL_PER_TIME = 50; // // ------------------------------------------------------- function __LnDebtSystem_init(address _admin) public initializer { __LnAdminUpgradeable_init(_admin); } event UpdateAddressStorage(address oldAddr, address newAddr); event UpdateUserDebtLog(address addr, uint256 debtProportion, uint256 debtFactor); event PushDebtLog(uint256 index, uint256 newFactor); // ------------------ system config ---------------------- function updateAddressCache(LnAddressStorage _addressStorage) public override onlyAdmin { accessCtrl = LnAccessControl( _addressStorage.getAddressWithRequire("LnAccessControl", "LnAccessControl address not valid") ); assetSys = LnAssetSystem(_addressStorage.getAddressWithRequire("LnAssetSystem", "LnAssetSystem address not valid")); feeSystem = LnFeeSystem(_addressStorage.getAddressWithRequire("LnFeeSystem", "LnFeeSystem address not valid")); emit CachedAddressUpdated("LnAccessControl", address(accessCtrl)); emit CachedAddressUpdated("LnAssetSystem", address(assetSys)); emit CachedAddressUpdated("LnFeeSystem", address(feeSystem)); } // ----------------------------------------------- modifier OnlyDebtSystemRole(address _address) { require(accessCtrl.hasRole(accessCtrl.DEBT_SYSTEM(), _address), "Need debt system access role"); _; } function SetLastCloseFeePeriodAt(uint256 index) external OnlyDebtSystemRole(msg.sender) { require(index >= lastCloseAt, "Close index can not return to pass"); require(index <= debtCurrentIndex, "Can not close at future index"); lastCloseAt = index; } function _pushDebtFactor(uint256 _factor) private { if (debtCurrentIndex == 0 || lastDebtFactors[debtCurrentIndex - 1] == 0) { // init or all debt has be cleared, new set value will be one unit lastDebtFactors[debtCurrentIndex] = SafeDecimalMath.preciseUnit(); } else { lastDebtFactors[debtCurrentIndex] = lastDebtFactors[debtCurrentIndex - 1].multiplyDecimalRoundPrecise(_factor); } emit PushDebtLog(debtCurrentIndex, lastDebtFactors[debtCurrentIndex]); debtCurrentIndex = debtCurrentIndex.add(1); // delete out of date data if (lastDeletTo < lastCloseAt) { // safe check uint256 delNum = lastCloseAt - lastDeletTo; delNum = (delNum > MAX_DEL_PER_TIME) ? MAX_DEL_PER_TIME : delNum; // not delete all in one call, for saving someone fee. for (uint256 i = lastDeletTo; i < delNum; i++) { delete lastDebtFactors[i]; } lastDeletTo = lastDeletTo.add(delNum); } } function PushDebtFactor(uint256 _factor) external OnlyDebtSystemRole(msg.sender) { _pushDebtFactor(_factor); } function _updateUserDebt(address _user, uint256 _debtProportion) private { userDebtState[_user].debtProportion = _debtProportion; userDebtState[_user].debtFactor = _lastSystemDebtFactor(); emit UpdateUserDebtLog(_user, _debtProportion, userDebtState[_user].debtFactor); feeSystem.RecordUserDebt(_user, userDebtState[_user].debtProportion, userDebtState[_user].debtFactor); } // need update lastDebtFactors first function UpdateUserDebt(address _user, uint256 _debtProportion) external OnlyDebtSystemRole(msg.sender) { _updateUserDebt(_user, _debtProportion); } function UpdateDebt( address _user, uint256 _debtProportion, uint256 _factor ) external OnlyDebtSystemRole(msg.sender) { _pushDebtFactor(_factor); _updateUserDebt(_user, _debtProportion); } function GetUserDebtData(address _user) external view returns (uint256 debtProportion, uint256 debtFactor) { debtProportion = userDebtState[_user].debtProportion; debtFactor = userDebtState[_user].debtFactor; } function _lastSystemDebtFactor() private view returns (uint256) { if (debtCurrentIndex == 0) { return SafeDecimalMath.preciseUnit(); } return lastDebtFactors[debtCurrentIndex - 1]; } function LastSystemDebtFactor() external view returns (uint256) { return _lastSystemDebtFactor(); } function GetUserCurrentDebtProportion(address _user) public view returns (uint256) { uint256 debtProportion = userDebtState[_user].debtProportion; uint256 debtFactor = userDebtState[_user].debtFactor; if (debtProportion == 0) { return 0; } uint256 currentUserDebtProportion = _lastSystemDebtFactor().divideDecimalRoundPrecise(debtFactor).multiplyDecimalRoundPrecise(debtProportion); return currentUserDebtProportion; } /** * *@return [0] the debt balance of user. [1] system total asset in usd. */ function GetUserDebtBalanceInUsd(address _user) external view returns (uint256, uint256) { uint256 totalAssetSupplyInUsd = assetSys.totalAssetsInUsd(); uint256 debtProportion = userDebtState[_user].debtProportion; uint256 debtFactor = userDebtState[_user].debtFactor; if (debtProportion == 0) { return (0, totalAssetSupplyInUsd); } uint256 currentUserDebtProportion = _lastSystemDebtFactor().divideDecimalRoundPrecise(debtFactor).multiplyDecimalRoundPrecise(debtProportion); uint256 userDebtBalance = totalAssetSupplyInUsd .decimalToPreciseDecimal() .multiplyDecimalRoundPrecise(currentUserDebtProportion) .preciseDecimalToDecimal(); return (userDebtBalance, totalAssetSupplyInUsd); } // Reserved storage space to allow for layout changes in the future. uint256[42] private __gap; } /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() internal { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!_paused, "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(_paused, "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } } // 根据 LnCollateralSystem 的抵押资产计算相关抵押率,buildable lusd contract LnBuildBurnSystem is LnAdmin, Pausable, LnAddressCache { using SafeMath for uint; using SafeDecimalMath for uint; using Address for address; // ------------------------------------------------------- // need set before system running value. LnAssetUpgradeable private lUSDToken; // this contract need LnDebtSystem private debtSystem; LnAssetSystem private assetSys; LnPrices private priceGetter; LnCollateralSystem private collaterSys; LnConfig private mConfig; // ------------------------------------------------------- constructor(address admin, address _lUSDTokenAddr) public LnAdmin(admin) { lUSDToken = LnAssetUpgradeable(_lUSDTokenAddr); } function setPaused(bool _paused) external onlyAdmin { if (_paused) { _pause(); } else { _unpause(); } } function updateAddressCache(LnAddressStorage _addressStorage) public override onlyAdmin { priceGetter = LnPrices(_addressStorage.getAddressWithRequire("LnPrices", "LnPrices address not valid")); debtSystem = LnDebtSystem(_addressStorage.getAddressWithRequire("LnDebtSystem", "LnDebtSystem address not valid")); assetSys = LnAssetSystem(_addressStorage.getAddressWithRequire("LnAssetSystem", "LnAssetSystem address not valid")); address payable collateralAddress = payable(_addressStorage.getAddressWithRequire("LnCollateralSystem", "LnCollateralSystem address not valid")); collaterSys = LnCollateralSystem(collateralAddress); mConfig = LnConfig(_addressStorage.getAddressWithRequire("LnConfig", "LnConfig address not valid")); emit CachedAddressUpdated("LnPrices", address(priceGetter)); emit CachedAddressUpdated("LnDebtSystem", address(debtSystem)); emit CachedAddressUpdated("LnAssetSystem", address(assetSys)); emit CachedAddressUpdated("LnCollateralSystem", address(collaterSys)); emit CachedAddressUpdated("LnConfig", address(mConfig)); } function SetLusdTokenAddress(address _address) public onlyAdmin { emit UpdateLusdToken(address(lUSDToken), _address); lUSDToken = LnAssetUpgradeable(_address); } event UpdateLusdToken(address oldAddr, address newAddr); function MaxCanBuildAsset(address user) public view returns (uint256) { uint256 buildRatio = mConfig.getUint(mConfig.BUILD_RATIO()); uint256 maxCanBuild = collaterSys.MaxRedeemableInUsd(user).mul(buildRatio).div(SafeDecimalMath.unit()); return maxCanBuild; } // build lusd function BuildAsset(uint256 amount) public whenNotPaused returns (bool) { address user = msg.sender; uint256 buildRatio = mConfig.getUint(mConfig.BUILD_RATIO()); uint256 maxCanBuild = collaterSys.MaxRedeemableInUsd(user).multiplyDecimal(buildRatio); require(amount <= maxCanBuild, "Build amount too big, you need more collateral"); // calc debt (uint256 oldUserDebtBalance, uint256 totalAssetSupplyInUsd) = debtSystem.GetUserDebtBalanceInUsd(user); uint256 newTotalAssetSupply = totalAssetSupplyInUsd.add(amount); // update debt data uint256 buildDebtProportion = amount.divideDecimalRoundPrecise(newTotalAssetSupply); // debtPercentage uint oldTotalProportion = SafeDecimalMath.preciseUnit().sub(buildDebtProportion); // uint256 newUserDebtProportion = buildDebtProportion; if (oldUserDebtBalance > 0) { newUserDebtProportion = oldUserDebtBalance.add(amount).divideDecimalRoundPrecise(newTotalAssetSupply); } // update debt debtSystem.UpdateDebt(user, newUserDebtProportion, oldTotalProportion); // mint asset lUSDToken.mint(user, amount); return true; } function BuildMaxAsset() external whenNotPaused { address user = msg.sender; uint256 max = MaxCanBuildAsset(user); BuildAsset(max); } function _burnAsset(address user, uint256 amount) internal { //uint256 buildRatio = mConfig.getUint(mConfig.BUILD_RATIO()); require(amount > 0, "amount need > 0"); // calc debt (uint256 oldUserDebtBalance, uint256 totalAssetSupplyInUsd) = debtSystem.GetUserDebtBalanceInUsd(user); require(oldUserDebtBalance > 0, "no debt, no burn"); uint256 burnAmount = oldUserDebtBalance < amount ? oldUserDebtBalance : amount; // burn asset lUSDToken.burn(user, burnAmount); uint newTotalDebtIssued = totalAssetSupplyInUsd.sub(burnAmount); uint oldTotalProportion = 0; if (newTotalDebtIssued > 0) { uint debtPercentage = burnAmount.divideDecimalRoundPrecise(newTotalDebtIssued); oldTotalProportion = SafeDecimalMath.preciseUnit().add(debtPercentage); } uint256 newUserDebtProportion = 0; if (oldUserDebtBalance > burnAmount) { uint newDebt = oldUserDebtBalance.sub(burnAmount); newUserDebtProportion = newDebt.divideDecimalRoundPrecise(newTotalDebtIssued); } // update debt debtSystem.UpdateDebt(user, newUserDebtProportion, oldTotalProportion); } // burn function BurnAsset(uint256 amount) external whenNotPaused returns (bool) { address user = msg.sender; _burnAsset(user, amount); return true; } //所有 // function MaxAssetToTarget(address user) external view returns(uint256) { // uint256 buildRatio = mConfig.getUint(mConfig.BUILD_RATIO()); // uint256 totalCollateral = collaterSys.GetUserTotalCollateralInUsd(user); // } // burn to target ratio function BurnAssetToTarget() external whenNotPaused returns (bool) { address user = msg.sender; uint256 buildRatio = mConfig.getUint(mConfig.BUILD_RATIO()); uint256 totalCollateral = collaterSys.GetUserTotalCollateralInUsd(user); uint256 maxBuildAssetToTarget = totalCollateral.multiplyDecimal(buildRatio); (uint256 debtAsset, ) = debtSystem.GetUserDebtBalanceInUsd(user); require(debtAsset > maxBuildAssetToTarget, "You maybe want build to target"); uint256 needBurn = debtAsset.sub(maxBuildAssetToTarget); uint balance = lUSDToken.balanceOf(user); // burn as many as possible if (balance < needBurn) { needBurn = balance; } _burnAsset(user, needBurn); return true; } } // 单纯抵押进来 // 赎回时需要 债务率良好才能赎回, 赎回部分能保持债务率高于目标债务率 contract LnCollateralSystem is LnAdminUpgradeable, PausableUpgradeable, LnAddressCache { using SafeMath for uint; using SafeDecimalMath for uint; using AddressUpgradeable for address; // ------------------------------------------------------- // need set before system running value. LnPrices public priceGetter; LnDebtSystem public debtSystem; LnBuildBurnSystem public buildBurnSystem; LnConfig public mConfig; LnRewardLocker public mRewardLocker; bytes32 public constant Currency_ETH = "ETH"; bytes32 public constant Currency_LINA = "LINA"; // ------------------------------------------------------- uint256 public uniqueId; // use log struct TokenInfo { address tokenAddr; uint256 minCollateral; // min collateral amount. uint256 totalCollateral; bool bClose; // TODO : 为了防止价格波动,另外再加个折扣价? } mapping(bytes32 => TokenInfo) public tokenInfos; bytes32[] public tokenSymbol; // keys of tokenInfos, use to iteration struct CollateralData { uint256 collateral; // total collateral } // [user] => ([token=> collateraldata]) mapping(address => mapping(bytes32 => CollateralData)) public userCollateralData; // ------------------------------------------------------- function __LnCollateralSystem_init(address _admin) public initializer { __LnAdminUpgradeable_init(_admin); } function setPaused(bool _paused) external onlyAdmin { if (_paused) { _pause(); } else { _unpause(); } } // ------------------ system config ---------------------- function updateAddressCache(LnAddressStorage _addressStorage) public override onlyAdmin { priceGetter = LnPrices(_addressStorage.getAddressWithRequire("LnPrices", "LnPrices address not valid")); debtSystem = LnDebtSystem(_addressStorage.getAddressWithRequire("LnDebtSystem", "LnDebtSystem address not valid")); buildBurnSystem = LnBuildBurnSystem( _addressStorage.getAddressWithRequire("LnBuildBurnSystem", "LnBuildBurnSystem address not valid") ); mConfig = LnConfig(_addressStorage.getAddressWithRequire("LnConfig", "LnConfig address not valid")); mRewardLocker = LnRewardLocker( _addressStorage.getAddressWithRequire("LnRewardLocker", "LnRewardLocker address not valid") ); emit CachedAddressUpdated("LnPrices", address(priceGetter)); emit CachedAddressUpdated("LnDebtSystem", address(debtSystem)); emit CachedAddressUpdated("LnBuildBurnSystem", address(buildBurnSystem)); emit CachedAddressUpdated("LnConfig", address(mConfig)); emit CachedAddressUpdated("LnRewardLocker", address(mRewardLocker)); } function updateTokenInfo( bytes32 _currency, address _tokenAddr, uint256 _minCollateral, bool _close ) private returns (bool) { require(_currency[0] != 0, "symbol cannot empty"); require(_currency != Currency_ETH, "ETH is used by system"); require(_tokenAddr != address(0), "token address cannot zero"); require(_tokenAddr.isContract(), "token address is not a contract"); if (tokenInfos[_currency].tokenAddr == address(0)) { // new token tokenSymbol.push(_currency); } uint256 totalCollateral = tokenInfos[_currency].totalCollateral; tokenInfos[_currency] = TokenInfo({ tokenAddr: _tokenAddr, minCollateral: _minCollateral, totalCollateral: totalCollateral, bClose: _close }); emit UpdateTokenSetting(_currency, _tokenAddr, _minCollateral, _close); return true; } // delete token info? need to handle it's staking data. function UpdateTokenInfo( bytes32 _currency, address _tokenAddr, uint256 _minCollateral, bool _close ) external onlyAdmin returns (bool) { return updateTokenInfo(_currency, _tokenAddr, _minCollateral, _close); } function UpdateTokenInfos( bytes32[] calldata _symbols, address[] calldata _tokenAddrs, uint256[] calldata _minCollateral, bool[] calldata _closes ) external onlyAdmin returns (bool) { require(_symbols.length == _tokenAddrs.length, "length of array not eq"); require(_symbols.length == _minCollateral.length, "length of array not eq"); require(_symbols.length == _closes.length, "length of array not eq"); for (uint256 i = 0; i < _symbols.length; i++) { updateTokenInfo(_symbols[i], _tokenAddrs[i], _minCollateral[i], _closes[i]); } return true; } // ------------------------------------------------------------------------ function GetSystemTotalCollateralInUsd() public view returns (uint256 rTotal) { for (uint256 i = 0; i < tokenSymbol.length; i++) { bytes32 currency = tokenSymbol[i]; if (tokenInfos[currency].totalCollateral > 0) { // this check for avoid calling getPrice when collateral is zero if (Currency_LINA == currency) { uint256 totallina = tokenInfos[currency].totalCollateral.add(mRewardLocker.totalNeedToReward()); rTotal = rTotal.add(totallina.multiplyDecimal(priceGetter.getPrice(currency))); } else { rTotal = rTotal.add( tokenInfos[currency].totalCollateral.multiplyDecimal(priceGetter.getPrice(currency)) ); } } } if (address(this).balance > 0) { rTotal = rTotal.add(address(this).balance.multiplyDecimal(priceGetter.getPrice(Currency_ETH))); } } function GetUserTotalCollateralInUsd(address _user) public view returns (uint256 rTotal) { for (uint256 i = 0; i < tokenSymbol.length; i++) { bytes32 currency = tokenSymbol[i]; if (userCollateralData[_user][currency].collateral > 0) { if (Currency_LINA == currency) { uint256 totallina = userCollateralData[_user][currency].collateral.add(mRewardLocker.balanceOf(_user)); rTotal = rTotal.add(totallina.multiplyDecimal(priceGetter.getPrice(currency))); } else { rTotal = rTotal.add( userCollateralData[_user][currency].collateral.multiplyDecimal(priceGetter.getPrice(currency)) ); } } } if (userCollateralData[_user][Currency_ETH].collateral > 0) { rTotal = rTotal.add( userCollateralData[_user][Currency_ETH].collateral.multiplyDecimal(priceGetter.getPrice(Currency_ETH)) ); } } function GetUserCollateral(address _user, bytes32 _currency) external view returns (uint256) { if (Currency_LINA != _currency) { return userCollateralData[_user][_currency].collateral; } return mRewardLocker.balanceOf(_user).add(userCollateralData[_user][_currency].collateral); } // NOTE: LINA collateral not include reward in locker function GetUserCollaterals(address _user) external view returns (bytes32[] memory, uint256[] memory) { bytes32[] memory rCurrency = new bytes32[](tokenSymbol.length + 1); uint256[] memory rAmount = new uint256[](tokenSymbol.length + 1); uint256 retSize = 0; for (uint256 i = 0; i < tokenSymbol.length; i++) { bytes32 currency = tokenSymbol[i]; if (userCollateralData[_user][currency].collateral > 0) { rCurrency[retSize] = currency; rAmount[retSize] = userCollateralData[_user][currency].collateral; retSize++; } } if (userCollateralData[_user][Currency_ETH].collateral > 0) { rCurrency[retSize] = Currency_ETH; rAmount[retSize] = userCollateralData[_user][Currency_ETH].collateral; retSize++; } return (rCurrency, rAmount); } /** * @dev A temporary method for migrating LINA tokens from LnSimpleStaking to LnCollateralSystem * without user intervention. */ function migrateCollateral( bytes32 _currency, address[] calldata _users, uint256[] calldata _amounts ) external onlyAdmin returns (bool) { require(tokenInfos[_currency].tokenAddr.isContract(), "Invalid token symbol"); TokenInfo storage tokeninfo = tokenInfos[_currency]; require(tokeninfo.bClose == false, "This token is closed"); require(_users.length == _amounts.length, "Length mismatch"); for (uint256 ind = 0; ind < _amounts.length; ind++) { address user = _users[ind]; uint256 amount = _amounts[ind]; userCollateralData[user][_currency].collateral = userCollateralData[user][_currency].collateral.add(amount); tokeninfo.totalCollateral = tokeninfo.totalCollateral.add(amount); emit CollateralLog(user, _currency, amount, userCollateralData[user][_currency].collateral); } } // need approve function Collateral(bytes32 _currency, uint256 _amount) external whenNotPaused returns (bool) { require(tokenInfos[_currency].tokenAddr.isContract(), "Invalid token symbol"); TokenInfo storage tokeninfo = tokenInfos[_currency]; require(_amount > tokeninfo.minCollateral, "Collateral amount too small"); require(tokeninfo.bClose == false, "This token is closed"); address user = msg.sender; IERC20 erc20 = IERC20(tokenInfos[_currency].tokenAddr); require(erc20.balanceOf(user) >= _amount, "insufficient balance"); require(erc20.allowance(user, address(this)) >= _amount, "insufficient allowance, need approve more amount"); erc20.transferFrom(user, address(this), _amount); userCollateralData[user][_currency].collateral = userCollateralData[user][_currency].collateral.add(_amount); tokeninfo.totalCollateral = tokeninfo.totalCollateral.add(_amount); emit CollateralLog(user, _currency, _amount, userCollateralData[user][_currency].collateral); return true; } function IsSatisfyTargetRatio(address _user) public view returns (bool) { (uint256 debtBalance, ) = debtSystem.GetUserDebtBalanceInUsd(_user); if (debtBalance == 0) { return true; } uint256 buildRatio = mConfig.getUint(mConfig.BUILD_RATIO()); uint256 totalCollateralInUsd = GetUserTotalCollateralInUsd(_user); if (totalCollateralInUsd == 0) { return false; } uint256 myratio = debtBalance.divideDecimal(totalCollateralInUsd); return myratio <= buildRatio; } // 满足最低抵押率的情况下可最大赎回的资产 TODO: return multi value function MaxRedeemableInUsd(address _user) public view returns (uint256) { uint256 totalCollateralInUsd = GetUserTotalCollateralInUsd(_user); (uint256 debtBalance, ) = debtSystem.GetUserDebtBalanceInUsd(_user); if (debtBalance == 0) { return totalCollateralInUsd; } uint256 buildRatio = mConfig.getUint(mConfig.BUILD_RATIO()); uint256 minCollateral = debtBalance.divideDecimal(buildRatio); if (totalCollateralInUsd < minCollateral) { return 0; } return totalCollateralInUsd.sub(minCollateral); } function MaxRedeemable(address user, bytes32 _currency) public view returns (uint256) { uint256 maxRedeemableInUsd = MaxRedeemableInUsd(user); uint256 maxRedeem = maxRedeemableInUsd.divideDecimal(priceGetter.getPrice(_currency)); if (maxRedeem > userCollateralData[user][_currency].collateral) { maxRedeem = userCollateralData[user][_currency].collateral; } if (Currency_LINA != _currency) { return maxRedeem; } uint256 lockedLina = mRewardLocker.balanceOf(user); if (maxRedeem <= lockedLina) { return 0; } return maxRedeem.sub(lockedLina); } function RedeemMax(bytes32 _currency) external whenNotPaused { address user = msg.sender; uint256 maxRedeem = MaxRedeemable(user, _currency); _Redeem(user, _currency, maxRedeem); } function _Redeem( address user, bytes32 _currency, uint256 _amount ) internal { require(_amount <= userCollateralData[user][_currency].collateral, "Can not redeem more than collateral"); require(_amount > 0, "Redeem amount need larger than zero"); uint256 maxRedeemableInUsd = MaxRedeemableInUsd(user); uint256 maxRedeem = maxRedeemableInUsd.divideDecimal(priceGetter.getPrice(_currency)); require(_amount <= maxRedeem, "Because lower collateral ratio, can not redeem too much"); userCollateralData[user][_currency].collateral = userCollateralData[user][_currency].collateral.sub(_amount); TokenInfo storage tokeninfo = tokenInfos[_currency]; tokeninfo.totalCollateral = tokeninfo.totalCollateral.sub(_amount); IERC20(tokenInfos[_currency].tokenAddr).transfer(user, _amount); emit RedeemCollateral(user, _currency, _amount, userCollateralData[user][_currency].collateral); } // 1. After redeem, collateral ratio need bigger than target ratio. // 2. Cannot redeem more than collateral. function Redeem(bytes32 _currency, uint256 _amount) public whenNotPaused returns (bool) { address user = msg.sender; _Redeem(user, _currency, _amount); return true; } receive() external payable whenNotPaused { address user = msg.sender; uint256 ethAmount = msg.value; _CollateralEth(user, ethAmount); } function _CollateralEth(address user, uint256 ethAmount) internal { require(ethAmount > 0, "ETH amount need more than zero"); userCollateralData[user][Currency_ETH].collateral = userCollateralData[user][Currency_ETH].collateral.add(ethAmount); emit CollateralLog(user, Currency_ETH, ethAmount, userCollateralData[user][Currency_ETH].collateral); } // payable eth receive, function CollateralEth() external payable whenNotPaused returns (bool) { address user = msg.sender; uint256 ethAmount = msg.value; _CollateralEth(user, ethAmount); return true; } function RedeemETH(uint256 _amount) external whenNotPaused returns (bool) { address payable user = msg.sender; require(_amount <= userCollateralData[user][Currency_ETH].collateral, "Can not redeem more than collateral"); require(_amount > 0, "Redeem amount need larger than zero"); uint256 maxRedeemableInUsd = MaxRedeemableInUsd(user); uint256 maxRedeem = maxRedeemableInUsd.divideDecimal(priceGetter.getPrice(Currency_ETH)); require(_amount <= maxRedeem, "Because lower collateral ratio, can not redeem too much"); userCollateralData[user][Currency_ETH].collateral = userCollateralData[user][Currency_ETH].collateral.sub(_amount); user.transfer(_amount); emit RedeemCollateral(user, Currency_ETH, _amount, userCollateralData[user][Currency_ETH].collateral); return true; } event UpdateTokenSetting(bytes32 symbol, address tokenAddr, uint256 minCollateral, bool close); event CollateralLog(address user, bytes32 _currency, uint256 _amount, uint256 _userTotal); event RedeemCollateral(address user, bytes32 _currency, uint256 _amount, uint256 _userTotal); // Reserved storage space to allow for layout changes in the future. uint256[41] private __gap; }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"CachedAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldCandidate","type":"address"},{"indexed":false,"internalType":"address","name":"newCandidate","type":"address"}],"name":"CandidateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bytes32","name":"_currency","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_userTotal","type":"uint256"}],"name":"CollateralLog","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bytes32","name":"_currency","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_userTotal","type":"uint256"}],"name":"RedeemCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"symbol","type":"bytes32"},{"indexed":false,"internalType":"address","name":"tokenAddr","type":"address"},{"indexed":false,"internalType":"uint256","name":"minCollateral","type":"uint256"},{"indexed":false,"internalType":"bool","name":"close","type":"bool"}],"name":"UpdateTokenSetting","type":"event"},{"inputs":[{"internalType":"bytes32","name":"_currency","type":"bytes32"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Collateral","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"CollateralEth","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"Currency_ETH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"Currency_LINA","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GetSystemTotalCollateralInUsd","outputs":[{"internalType":"uint256","name":"rTotal","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"bytes32","name":"_currency","type":"bytes32"}],"name":"GetUserCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"GetUserCollaterals","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"GetUserTotalCollateralInUsd","outputs":[{"internalType":"uint256","name":"rTotal","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"IsSatisfyTargetRatio","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bytes32","name":"_currency","type":"bytes32"}],"name":"MaxRedeemable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"MaxRedeemableInUsd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_currency","type":"bytes32"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Redeem","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"RedeemETH","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_currency","type":"bytes32"}],"name":"RedeemMax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_currency","type":"bytes32"},{"internalType":"address","name":"_tokenAddr","type":"address"},{"internalType":"uint256","name":"_minCollateral","type":"uint256"},{"internalType":"bool","name":"_close","type":"bool"}],"name":"UpdateTokenInfo","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_symbols","type":"bytes32[]"},{"internalType":"address[]","name":"_tokenAddrs","type":"address[]"},{"internalType":"uint256[]","name":"_minCollateral","type":"uint256[]"},{"internalType":"bool[]","name":"_closes","type":"bool[]"}],"name":"UpdateTokenInfos","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"__LnAdminUpgradeable_init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"__LnCollateralSystem_init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"becomeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buildBurnSystem","outputs":[{"internalType":"contract LnBuildBurnSystem","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"candidate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"debtSystem","outputs":[{"internalType":"contract LnDebtSystem","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mConfig","outputs":[{"internalType":"contract LnConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mRewardLocker","outputs":[{"internalType":"contract LnRewardLocker","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_currency","type":"bytes32"},{"internalType":"address[]","name":"_users","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"migrateCollateral","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceGetter","outputs":[{"internalType":"contract LnPrices","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_candidate","type":"address"}],"name":"setCandidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenInfos","outputs":[{"internalType":"address","name":"tokenAddr","type":"address"},{"internalType":"uint256","name":"minCollateral","type":"uint256"},{"internalType":"uint256","name":"totalCollateral","type":"uint256"},{"internalType":"bool","name":"bClose","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenSymbol","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniqueId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract LnAddressStorage","name":"_addressStorage","type":"address"}],"name":"updateAddressCache","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"userCollateralData","outputs":[{"internalType":"uint256","name":"collateral","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801561001057600080fd5b50614db4806100206000396000f3fe6080604052600436106102385760003560e01c806375f93fa811610138578063c19bff31116100b0578063f563feec1161007f578063f851a44011610064578063f851a44014610b39578063f867831314610b4e578063ff06a5d414610b63576102bf565b8063f563feec14610986578063f72d5426146109c6576102bf565b8063c19bff31146108d1578063c91facaf14610901578063ceed1b9014610947578063e05b0cc21461095c576102bf565b806390f1f17b11610107578063acb0c604116100ec578063acb0c6041461081b578063bc65d43414610861578063c08f73b6146108a1576102bf565b806390f1f17b1461079d5780639235f45f14610806576102bf565b806375f93fa81461062f5780637e2748f6146106445780637fd1b5ab1461071d5780638e118b831461075d576102bf565b80634bf70272116101cb5780635a5f14c81161019a5780635d521a341161017f5780635d521a34146105f0578063629c52a9146106055780636c8381f81461061a576102bf565b80635a5f14c81461059b5780635c975abb146105db576102bf565b80634bf702721461041c57806351260791146104f257806352adb88914610532578063592315d114610547576102bf565b806325971dff1161020757806325971dff146103ac57806342fc00f4146103c157806346a00af9146103c95780634b86f75f14610407576102bf565b806307880b7f146102c4578063169e02fc1461030657806316c38b3c1461034457806317fd1d8014610370576102bf565b366102bf5760645460ff16156102af57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b33346102bb8282610ba9565b5050005b600080fd5b3480156102d057600080fd5b50610304600480360360208110156102e757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610d13565b005b34801561031257600080fd5b506103306004803603602081101561032957600080fd5b5035610e10565b604080519115158252519081900360200190f35b34801561035057600080fd5b506103046004803603602081101561036757600080fd5b50351515611220565b34801561037c57600080fd5b5061039a6004803603602081101561039357600080fd5b50356112b4565b60408051918252519081900360200190f35b3480156103b857600080fd5b506103046112d2565b6103306113d8565b3480156103d557600080fd5b506103de611463565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561041357600080fd5b506103de61147f565b34801561042857600080fd5b506103306004803603606081101561043f57600080fd5b8135919081019060408101602082013564010000000081111561046157600080fd5b82018360208201111561047357600080fd5b8035906020019184602083028401116401000000008311171561049557600080fd5b9193909290916020810190356401000000008111156104b357600080fd5b8201836020820111156104c557600080fd5b803590602001918460208302840111640100000000831117156104e757600080fd5b50909250905061149b565b3480156104fe57600080fd5b5061039a6004803603602081101561051557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661181d565b34801561053e57600080fd5b506103de611ca9565b34801561055357600080fd5b506103306004803603608081101561056a57600080fd5b5080359073ffffffffffffffffffffffffffffffffffffffff60208201351690604081013590606001351515611cc5565b3480156105a757600080fd5b50610304600480360360208110156105be57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611d51565b3480156105e757600080fd5b5061033061256f565b3480156105fc57600080fd5b5061039a612578565b34801561061157600080fd5b5061039a61259c565b34801561062657600080fd5b506103de6125a2565b34801561063b57600080fd5b5061039a6125be565b34801561065057600080fd5b506106846004803603602081101561066757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612904565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156106c85781810151838201526020016106b0565b50505050905001838103825284818151815260200191508051906020019060200280838360005b838110156107075781810151838201526020016106ef565b5050505090500194505050505060405180910390f35b34801561072957600080fd5b506103046004803603602081101561074057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612b7a565b34801561076957600080fd5b506103046004803603602081101561078057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612c98565b3480156107a957600080fd5b506107c7600480360360208110156107c057600080fd5b5035612eb3565b6040805173ffffffffffffffffffffffffffffffffffffffff909516855260208501939093528383019190915215156060830152519081900360800190f35b34801561081257600080fd5b506103de612ef4565b34801561082757600080fd5b5061039a6004803603604081101561083e57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135612f10565b34801561086d57600080fd5b506103306004803603602081101561088457600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612f2d565b3480156108ad57600080fd5b50610330600480360360408110156108c457600080fd5b5080359060200135613137565b3480156108dd57600080fd5b50610330600480360360408110156108f457600080fd5b50803590602001356136f6565b34801561090d57600080fd5b5061039a6004803603604081101561092457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135613781565b34801561095357600080fd5b506103de613970565b34801561096857600080fd5b506103046004803603602081101561097f57600080fd5b503561398c565b34801561099257600080fd5b5061039a600480360360208110156109a957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16613a1d565b3480156109d257600080fd5b50610330600480360360808110156109e957600080fd5b810190602081018135640100000000811115610a0457600080fd5b820183602082011115610a1657600080fd5b80359060200191846020830284011164010000000083111715610a3857600080fd5b919390929091602081019035640100000000811115610a5657600080fd5b820183602082011115610a6857600080fd5b80359060200191846020830284011164010000000083111715610a8a57600080fd5b919390929091602081019035640100000000811115610aa857600080fd5b820183602082011115610aba57600080fd5b80359060200191846020830284011164010000000083111715610adc57600080fd5b919390929091602081019035640100000000811115610afa57600080fd5b820183602082011115610b0c57600080fd5b80359060200191846020830284011164010000000083111715610b2e57600080fd5b509092509050613c28565b348015610b4557600080fd5b506103de613e79565b348015610b5a57600080fd5b5061039a613e9b565b348015610b6f57600080fd5b5061039a60048036036040811015610b8657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135613ebf565b60008111610c1857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f45544820616d6f756e74206e656564206d6f7265207468616e207a65726f0000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152609e602090815260408083207f45544800000000000000000000000000000000000000000000000000000000008452909152902054610c739082613fea565b73ffffffffffffffffffffffffffffffffffffffff83166000818152609e602090815260408083207f455448000000000000000000000000000000000000000000000000000000000080855290835292819020859055805193845290830191909152818101849052606082019290925290517fe25398ee94a2ec2dde5992b338a76ddd3a7af4d596cf2d00feba7770b31de2999181900360800190a15050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314610d89576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526043815260200180614d056043913960600191505060405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831617928390556040805192821680845293909116602083015280517f7f730391c4f0fa1bea34bcb9bff8c30a079b21a0359759160cb990648ab84c729281900390910190a15050565b60645460009060ff1615610e8557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b336000818152609e602090815260408083207f45544800000000000000000000000000000000000000000000000000000000008452909152902054831115610f18576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180614ce26023913960400191505060405180910390fd5b60008311610f71576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180614cbf6023913960400191505060405180910390fd5b6000610f7c82613a1d565b609654604080517f31d98b3f0000000000000000000000000000000000000000000000000000000081527f4554480000000000000000000000000000000000000000000000000000000000600482015290519293506000926110479273ffffffffffffffffffffffffffffffffffffffff16916331d98b3f916024808301926020929190829003018186803b15801561101457600080fd5b505afa158015611028573d6000803e3d6000fd5b505050506040513d602081101561103e57600080fd5b5051839061405e565b9050808511156110a2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526037815260200180614d486037913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000908152609e602090815260408083207f455448000000000000000000000000000000000000000000000000000000000084529091529020546110fd908661407c565b73ffffffffffffffffffffffffffffffffffffffff84166000818152609e602090815260408083207f45544800000000000000000000000000000000000000000000000000000000008452909152808220939093559151909187156108fc02918891818181858888f1935050505015801561117c573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff83166000818152609e602090815260408083207f455448000000000000000000000000000000000000000000000000000000000080855290835292819020548151948552918401929092528282018890526060830152517ffa659da0063f4e5cf39c3b6dae863e789ab69f82e82925c28cae633a81b2b65d9181900360800190a1600193505050505b919050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314611296576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526043815260200180614d056043913960600191505060405180910390fd5b80156112a9576112a46140be565b6112b1565b6112b16141ae565b50565b609d81815481106112c157fe5b600091825260209091200154905081565b60015473ffffffffffffffffffffffffffffffffffffffff163314611342576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526033815260200180614c1a6033913960400191505060405180910390fd5b6000805460015473ffffffffffffffffffffffffffffffffffffffff908116620100009081027fffffffffffffffffffff0000000000000000000000000000000000000000ffff8416179384905560408051938290048316808552919094049091166020830152825190927f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f928290030190a150565b60645460009060ff161561144d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b33346114598282610ba9565b6001925050505b90565b60995473ffffffffffffffffffffffffffffffffffffffff1681565b60975473ffffffffffffffffffffffffffffffffffffffff1681565b6000805462010000900473ffffffffffffffffffffffffffffffffffffffff163314611512576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526043815260200180614d056043913960600191505060405180910390fd5b6000868152609c60205260409020546115409073ffffffffffffffffffffffffffffffffffffffff16614270565b6115ab57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f496e76616c696420746f6b656e2073796d626f6c000000000000000000000000604482015290519081900360640190fd5b6000868152609c60205260409020600381015460ff161561162d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5468697320746f6b656e20697320636c6f736564000000000000000000000000604482015290519081900360640190fd5b84831461169b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4c656e677468206d69736d617463680000000000000000000000000000000000604482015290519081900360640190fd5b60005b838110156118125760008787838181106116b457fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff16905060008686848181106116e157fe5b90506020020135905061175081609e60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008d815260200190815260200160002060000154613fea90919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff83166000908152609e602090815260408083208e845290915290205560028401546117909082613fea565b600285015573ffffffffffffffffffffffffffffffffffffffff82166000818152609e602090815260408083208e84528252918290205482519384529083018d90528282018490526060830152517fe25398ee94a2ec2dde5992b338a76ddd3a7af4d596cf2d00feba7770b31de2999181900360800190a1505060010161169e565b505095945050505050565b6000805b609d54811015611b29576000609d828154811061183a57fe5b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff87168352609e8252604080842082855290925291205490915015611b2057807f4c494e41000000000000000000000000000000000000000000000000000000001415611a3957609a54604080517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152915160009361197d9316916370a08231916024808301926020929190829003018186803b15801561191a57600080fd5b505afa15801561192e573d6000803e3d6000fd5b505050506040513d602081101561194457600080fd5b505173ffffffffffffffffffffffffffffffffffffffff87166000908152609e6020908152604080832087845290915290205490613fea565b609654604080517f31d98b3f000000000000000000000000000000000000000000000000000000008152600481018690529051929350611a3192611a2a9273ffffffffffffffffffffffffffffffffffffffff16916331d98b3f916024808301926020929190829003018186803b1580156119f757600080fd5b505afa158015611a0b573d6000803e3d6000fd5b505050506040513d6020811015611a2157600080fd5b50518390614276565b8590613fea565b935050611b20565b609654604080517f31d98b3f000000000000000000000000000000000000000000000000000000008152600481018490529051611b1d92611b169273ffffffffffffffffffffffffffffffffffffffff909116916331d98b3f91602480820192602092909190829003018186803b158015611ab357600080fd5b505afa158015611ac7573d6000803e3d6000fd5b505050506040513d6020811015611add57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff87166000908152609e6020908152604080832087845290915290205490614276565b8490613fea565b92505b50600101611821565b5073ffffffffffffffffffffffffffffffffffffffff82166000908152609e602090815260408083207f455448000000000000000000000000000000000000000000000000000000000084529091529020541561121b57609654604080517f31d98b3f0000000000000000000000000000000000000000000000000000000081527f455448000000000000000000000000000000000000000000000000000000000060048201529051611ca392611c9c9273ffffffffffffffffffffffffffffffffffffffff909116916331d98b3f91602480820192602092909190829003018186803b158015611c1957600080fd5b505afa158015611c2d573d6000803e3d6000fd5b505050506040513d6020811015611c4357600080fd5b505173ffffffffffffffffffffffffffffffffffffffff85166000908152609e602090815260408083207f4554480000000000000000000000000000000000000000000000000000000000845290915290205490614276565b8290613fea565b92915050565b60985473ffffffffffffffffffffffffffffffffffffffff1681565b6000805462010000900473ffffffffffffffffffffffffffffffffffffffff163314611d3c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526043815260200180614d056043913960600191505060405180910390fd5b611d488585858561429a565b95945050505050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314611dc7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526043815260200180614d056043913960600191505060405180910390fd5b604080517f768911da0000000000000000000000000000000000000000000000000000000081527f4c6e507269636573000000000000000000000000000000000000000000000000600482015260248101829052601a60448201527f4c6e5072696365732061646472657373206e6f742076616c69640000000000006064820152905173ffffffffffffffffffffffffffffffffffffffff83169163768911da916084808301926020929190829003018186803b158015611e8757600080fd5b505afa158015611e9b573d6000803e3d6000fd5b505050506040513d6020811015611eb157600080fd5b5051609680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055604080517f768911da0000000000000000000000000000000000000000000000000000000081527f4c6e4465627453797374656d0000000000000000000000000000000000000000600482015260248101829052601e60448201527f4c6e4465627453797374656d2061646472657373206e6f742076616c69640000606482015290519183169163768911da91608480820192602092909190829003018186803b158015611fa157600080fd5b505afa158015611fb5573d6000803e3d6000fd5b505050506040513d6020811015611fcb57600080fd5b5051609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055604080517f768911da0000000000000000000000000000000000000000000000000000000081527f4c6e4275696c644275726e53797374656d00000000000000000000000000000060048201908152602482019283526023604483018190529385169363768911da93919260640190614c9c823960400191505060206040518083038186803b1580156120a057600080fd5b505afa1580156120b4573d6000803e3d6000fd5b505050506040513d60208110156120ca57600080fd5b5051609880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055604080517f768911da0000000000000000000000000000000000000000000000000000000081527f4c6e436f6e666967000000000000000000000000000000000000000000000000600482015260248101829052601a60448201527f4c6e436f6e6669672061646472657373206e6f742076616c6964000000000000606482015290519183169163768911da91608480820192602092909190829003018186803b1580156121ba57600080fd5b505afa1580156121ce573d6000803e3d6000fd5b505050506040513d60208110156121e457600080fd5b5051609980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055604080517f768911da0000000000000000000000000000000000000000000000000000000081527f4c6e5265776172644c6f636b65720000000000000000000000000000000000006004820152602481018290526020604482018190527f4c6e5265776172644c6f636b65722061646472657373206e6f742076616c6964606483015291519284169263768911da92608480840193919291829003018186803b1580156122d357600080fd5b505afa1580156122e7573d6000803e3d6000fd5b505050506040513d60208110156122fd57600080fd5b5051609a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055609654604080517f4c6e507269636573000000000000000000000000000000000000000000000000815291909216602082015281517f17b158864f8c520aff3282c940ec6a731d26235b9b00b651c0dd1dafb3170f5f929181900390910190a1609754604080517f4c6e4465627453797374656d0000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216602083015280517f17b158864f8c520aff3282c940ec6a731d26235b9b00b651c0dd1dafb3170f5f9281900390910190a1609854604080517f4c6e4275696c644275726e53797374656d000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216602083015280517f17b158864f8c520aff3282c940ec6a731d26235b9b00b651c0dd1dafb3170f5f9281900390910190a1609954604080517f4c6e436f6e666967000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216602083015280517f17b158864f8c520aff3282c940ec6a731d26235b9b00b651c0dd1dafb3170f5f9281900390910190a1609a54604080517f4c6e5265776172644c6f636b6572000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216602083015280517f17b158864f8c520aff3282c940ec6a731d26235b9b00b651c0dd1dafb3170f5f9281900390910190a150565b60645460ff1690565b7f455448000000000000000000000000000000000000000000000000000000000081565b609b5481565b60015473ffffffffffffffffffffffffffffffffffffffff1681565b6000805b609d5481101561282c576000609d82815481106125db57fe5b906000526020600020015490506000609c600083815260200190815260200160002060020154111561282357807f4c494e410000000000000000000000000000000000000000000000000000000014156127625760006126e0609a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16634bcdd1746040518163ffffffff1660e01b815260040160206040518083038186803b15801561269c57600080fd5b505afa1580156126b0573d6000803e3d6000fd5b505050506040513d60208110156126c657600080fd5b50516000848152609c602052604090206002015490613fea565b609654604080517f31d98b3f00000000000000000000000000000000000000000000000000000000815260048101869052905192935061275a92611a2a9273ffffffffffffffffffffffffffffffffffffffff16916331d98b3f916024808301926020929190829003018186803b1580156119f757600080fd5b935050612823565b609654604080517f31d98b3f00000000000000000000000000000000000000000000000000000000815260048101849052905161282092611b169273ffffffffffffffffffffffffffffffffffffffff909116916331d98b3f91602480820192602092909190829003018186803b1580156127dc57600080fd5b505afa1580156127f0573d6000803e3d6000fd5b505050506040513d602081101561280657600080fd5b50516000848152609c602052604090206002015490614276565b92505b506001016125c2565b50471561146057609654604080517f31d98b3f0000000000000000000000000000000000000000000000000000000081527f4554480000000000000000000000000000000000000000000000000000000000600482015290516128ff92611c9c9273ffffffffffffffffffffffffffffffffffffffff909116916331d98b3f91602480820192602092909190829003018186803b1580156128cc57600080fd5b505afa1580156128e0573d6000803e3d6000fd5b505050506040513d60208110156128f657600080fd5b50514790614276565b905090565b6060806060609d8054905060010167ffffffffffffffff8111801561292857600080fd5b50604051908082528060200260200182016040528015612952578160200160208202803683370190505b50609d5490915060609060010167ffffffffffffffff8111801561297557600080fd5b5060405190808252806020026020018201604052801561299f578160200160208202803683370190505b5090506000805b609d54811015612a72576000609d82815481106129bf57fe5b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8b168352609e8252604080842082855290925291205490915015612a695780858481518110612a0d57fe5b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff89166000908152609e8252604080822084835290925220548451859085908110612a5757fe5b60209081029190910101526001909201915b506001016129a6565b5073ffffffffffffffffffffffffffffffffffffffff86166000908152609e602090815260408083207f4554480000000000000000000000000000000000000000000000000000000000845290915290205415612b6f577f4554480000000000000000000000000000000000000000000000000000000000838281518110612af657fe5b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff87166000908152609e825260408082207f4554480000000000000000000000000000000000000000000000000000000000835290925220548251839083908110612b6057fe5b60209081029190910101526001015b509092509050915091565b600054610100900460ff1680612b935750612b93614681565b80612ba1575060005460ff16155b612bf6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180614c4d602e913960400191505060405180910390fd5b600054610100900460ff16158015612c5c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b612c6582612c98565b8015612c9457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b5050565b600054610100900460ff1680612cb15750612cb1614681565b80612cbf575060005460ff16155b612d14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180614c4d602e913960400191505060405180910390fd5b600054610100900460ff16158015612d7a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b73ffffffffffffffffffffffffffffffffffffffff8216612dfc57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4c6e41646d696e5570677261646561626c653a207a65726f2061646472657373604482015290519081900360640190fd5b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff851690810291909117825560408051928352602083019190915280517f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f9281900390910190a18015612c9457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555050565b609c60205260009081526040902080546001820154600283015460039093015473ffffffffffffffffffffffffffffffffffffffff90921692909160ff1684565b609a5473ffffffffffffffffffffffffffffffffffffffff1681565b609e60209081526000928352604080842090915290825290205481565b609754604080517f1882d09000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015282516000948594921692631882d090926024808301939192829003018186803b158015612fa057600080fd5b505afa158015612fb4573d6000803e3d6000fd5b505050506040513d6040811015612fca57600080fd5b5051905080612fdd57600191505061121b565b609954604080517f4d6daf04000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163bd02d0f5918391634d6daf04916004808301926020929190829003018186803b15801561305057600080fd5b505afa158015613064573d6000803e3d6000fd5b505050506040513d602081101561307a57600080fd5b5051604080517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526004810192909252516024808301926020929190829003018186803b1580156130d157600080fd5b505afa1580156130e5573d6000803e3d6000fd5b505050506040513d60208110156130fb57600080fd5b50519050600061310a8561181d565b90508061311d576000935050505061121b565b6000613129848361405e565b929092111595945050505050565b60645460009060ff16156131ac57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b6000838152609c60205260409020546131da9073ffffffffffffffffffffffffffffffffffffffff16614270565b61324557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f496e76616c696420746f6b656e2073796d626f6c000000000000000000000000604482015290519081900360640190fd5b6000838152609c60205260409020600181015483116132c557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f436f6c6c61746572616c20616d6f756e7420746f6f20736d616c6c0000000000604482015290519081900360640190fd5b600381015460ff161561333957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5468697320746f6b656e20697320636c6f736564000000000000000000000000604482015290519081900360640190fd5b6000848152609c60209081526040918290205482517f70a082310000000000000000000000000000000000000000000000000000000081523360048201819052935173ffffffffffffffffffffffffffffffffffffffff90921692879284926370a08231926024808301939192829003018186803b1580156133ba57600080fd5b505afa1580156133ce573d6000803e3d6000fd5b505050506040513d60208110156133e457600080fd5b5051101561345357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e73756666696369656e742062616c616e6365000000000000000000000000604482015290519081900360640190fd5b604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301523060248301529151879284169163dd62ed3e916044808301926020929190829003018186803b1580156134c957600080fd5b505afa1580156134dd573d6000803e3d6000fd5b505050506040513d60208110156134f357600080fd5b5051101561354c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526030815260200180614bea6030913960400191505060405180910390fd5b604080517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152306024830152604482018890529151918316916323b872dd916064808201926020929091908290030181600087803b1580156135cb57600080fd5b505af11580156135df573d6000803e3d6000fd5b505050506040513d60208110156135f557600080fd5b505073ffffffffffffffffffffffffffffffffffffffff82166000908152609e602090815260408083208984529091529020546136329086613fea565b73ffffffffffffffffffffffffffffffffffffffff83166000908152609e602090815260408083208a845290915290205560028301546136729086613fea565b600284015573ffffffffffffffffffffffffffffffffffffffff82166000818152609e602090815260408083208a84528252918290205482519384529083018990528282018890526060830152517fe25398ee94a2ec2dde5992b338a76ddd3a7af4d596cf2d00feba7770b31de2999181900360800190a150600195945050505050565b60645460009060ff161561376b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b33613777818585614687565b5060019392505050565b60008061378d84613a1d565b609654604080517f31d98b3f0000000000000000000000000000000000000000000000000000000081526004810187905290519293506000926138069273ffffffffffffffffffffffffffffffffffffffff16916331d98b3f916024808301926020929190829003018186803b15801561101457600080fd5b73ffffffffffffffffffffffffffffffffffffffff86166000908152609e60209081526040808320888452909152902054909150811115613874575073ffffffffffffffffffffffffffffffffffffffff84166000908152609e602090815260408083208684529091529020545b837f4c494e4100000000000000000000000000000000000000000000000000000000146138a4579150611ca39050565b609a54604080517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152915160009392909216916370a0823191602480820192602092909190829003018186803b15801561391b57600080fd5b505afa15801561392f573d6000803e3d6000fd5b505050506040513d602081101561394557600080fd5b5051905080821161395c5760009350505050611ca3565b613966828261407c565b9695505050505050565b60965473ffffffffffffffffffffffffffffffffffffffff1681565b60645460ff16156139fe57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b336000613a0b8284613781565b9050613a18828483614687565b505050565b600080613a298361181d565b609754604080517f1882d09000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301528251949550600094931692631882d09092602480840193919291829003018186803b158015613a9e57600080fd5b505afa158015613ab2573d6000803e3d6000fd5b505050506040513d6040811015613ac857600080fd5b5051905080613ad95750905061121b565b609954604080517f4d6daf04000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163bd02d0f5918391634d6daf04916004808301926020929190829003018186803b158015613b4c57600080fd5b505afa158015613b60573d6000803e3d6000fd5b505050506040513d6020811015613b7657600080fd5b5051604080517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526004810192909252516024808301926020929190829003018186803b158015613bcd57600080fd5b505afa158015613be1573d6000803e3d6000fd5b505050506040513d6020811015613bf757600080fd5b505190506000613c07838361405e565b905080841015613c1e57600094505050505061121b565b613966848261407c565b6000805462010000900473ffffffffffffffffffffffffffffffffffffffff163314613c9f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526043815260200180614d056043913960600191505060405180910390fd5b878614613d0d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6c656e677468206f66206172726179206e6f7420657100000000000000000000604482015290519081900360640190fd5b878414613d7b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6c656e677468206f66206172726179206e6f7420657100000000000000000000604482015290519081900360640190fd5b878214613de957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6c656e677468206f66206172726179206e6f7420657100000000000000000000604482015290519081900360640190fd5b60005b88811015613e6957613e608a8a83818110613e0357fe5b90506020020135898984818110613e1657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff16888885818110613e3f57fe5b90506020020135878786818110613e5257fe5b90506020020135151561429a565b50600101613dec565b5060019998505050505050505050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1681565b7f4c494e410000000000000000000000000000000000000000000000000000000081565b6000817f4c494e410000000000000000000000000000000000000000000000000000000014613f1f575073ffffffffffffffffffffffffffffffffffffffff82166000908152609e60209081526040808320848452909152902054611ca3565b73ffffffffffffffffffffffffffffffffffffffff8084166000818152609e6020908152604080832087845282529182902054609a5483517f70a0823100000000000000000000000000000000000000000000000000000000815260048101959095529251613fe395919493909116926370a08231926024808301939192829003018186803b158015613fb157600080fd5b505afa158015613fc5573d6000803e3d6000fd5b505050506040513d6020811015613fdb57600080fd5b505190613fea565b9392505050565b600082820183811015613fe357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000613fe38261407685670de0b6b3a7640000614a00565b90614a73565b6000613fe383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614ab5565b60645460ff161561413057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b606480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614184614b66565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190a1565b60645460ff1661421f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b606480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa614184614b66565b3b151590565b6000670de0b6b3a764000061428b8484614a00565b8161429257fe5b049392505050565b600084811a60f81b7fff000000000000000000000000000000000000000000000000000000000000001661432f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f73796d626f6c2063616e6e6f7420656d70747900000000000000000000000000604482015290519081900360640190fd5b7f45544800000000000000000000000000000000000000000000000000000000008514156143be57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f45544820697320757365642062792073797374656d0000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff841661444057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f746f6b656e20616464726573732063616e6e6f74207a65726f00000000000000604482015290519081900360640190fd5b61445f8473ffffffffffffffffffffffffffffffffffffffff16614270565b6144ca57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f746f6b656e2061646472657373206973206e6f74206120636f6e747261637400604482015290519081900360640190fd5b6000858152609c602052604090205473ffffffffffffffffffffffffffffffffffffffff1661452957609d80546001810182556000919091527fd26e832454299e9fabb89e0e5fffdc046d4e14431bc1bf607ffb2e8a1ddecf7b018590555b6000609c600087815260200190815260200160002060020154905060405180608001604052808673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001828152602001841515815250609c600088815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550602082015181600101556040820151816002015560608201518160030160006101000a81548160ff0219169083151502179055509050507fb8ccd92c8fb24731fb4c076a82ecc0f1ff41af213ec928f550aa42fa8e5aee8c86868686604051808581526020018473ffffffffffffffffffffffffffffffffffffffff168152602001838152602001821515815260200194505050505060405180910390a150600195945050505050565b303b1590565b73ffffffffffffffffffffffffffffffffffffffff83166000908152609e60209081526040808320858452909152902054811115614710576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180614ce26023913960400191505060405180910390fd5b60008111614769576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180614cbf6023913960400191505060405180910390fd5b600061477484613a1d565b609654604080517f31d98b3f0000000000000000000000000000000000000000000000000000000081526004810187905290519293506000926147ed9273ffffffffffffffffffffffffffffffffffffffff16916331d98b3f916024808301926020929190829003018186803b15801561101457600080fd5b905080831115614848576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526037815260200180614d486037913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff85166000908152609e60209081526040808320878452909152902054614883908461407c565b73ffffffffffffffffffffffffffffffffffffffff86166000908152609e60209081526040808320888452825280832093909355609c90522060028101546148cb908561407c565b60028201556000858152609c602090815260408083205481517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8b81166004830152602482018a90529251929091169363a9059cbb9360448084019491939192918390030190829087803b15801561495957600080fd5b505af115801561496d573d6000803e3d6000fd5b505050506040513d602081101561498357600080fd5b505073ffffffffffffffffffffffffffffffffffffffff86166000818152609e602090815260408083208984528252918290205482519384529083018890528282018790526060830152517ffa659da0063f4e5cf39c3b6dae863e789ab69f82e82925c28cae633a81b2b65d9181900360800190a1505050505050565b600082614a0f57506000611ca3565b82820282848281614a1c57fe5b0414613fe3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180614c7b6021913960400191505060405180910390fd5b6000613fe383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614b6a565b60008184841115614b5e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614b23578181015183820152602001614b0b565b50505050905090810190601f168015614b505780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b3390565b60008183614bd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315614b23578181015183820152602001614b0b565b506000838581614bdf57fe5b049594505050505056fe696e73756666696369656e7420616c6c6f77616e63652c206e65656420617070726f7665206d6f726520616d6f756e744c6e41646d696e5570677261646561626c653a206f6e6c792063616e6469646174652063616e206265636f6d652061646d696e496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774c6e4275696c644275726e53797374656d2061646472657373206e6f742076616c696452656465656d20616d6f756e74206e656564206c6172676572207468616e207a65726f43616e206e6f742072656465656d206d6f7265207468616e20636f6c6c61746572616c4c6e41646d696e5570677261646561626c653a206f6e6c792074686520636f6e74726163742061646d696e2063616e20706572666f726d207468697320616374696f6e42656361757365206c6f77657220636f6c6c61746572616c20726174696f2c2063616e206e6f742072656465656d20746f6f206d756368a26469706673582212200e0c79094e6fec2fadb511d661f8577099b7e4a9aef257bda9930a8cc70e72f864736f6c634300060c0033
Deployed Bytecode
0x6080604052600436106102385760003560e01c806375f93fa811610138578063c19bff31116100b0578063f563feec1161007f578063f851a44011610064578063f851a44014610b39578063f867831314610b4e578063ff06a5d414610b63576102bf565b8063f563feec14610986578063f72d5426146109c6576102bf565b8063c19bff31146108d1578063c91facaf14610901578063ceed1b9014610947578063e05b0cc21461095c576102bf565b806390f1f17b11610107578063acb0c604116100ec578063acb0c6041461081b578063bc65d43414610861578063c08f73b6146108a1576102bf565b806390f1f17b1461079d5780639235f45f14610806576102bf565b806375f93fa81461062f5780637e2748f6146106445780637fd1b5ab1461071d5780638e118b831461075d576102bf565b80634bf70272116101cb5780635a5f14c81161019a5780635d521a341161017f5780635d521a34146105f0578063629c52a9146106055780636c8381f81461061a576102bf565b80635a5f14c81461059b5780635c975abb146105db576102bf565b80634bf702721461041c57806351260791146104f257806352adb88914610532578063592315d114610547576102bf565b806325971dff1161020757806325971dff146103ac57806342fc00f4146103c157806346a00af9146103c95780634b86f75f14610407576102bf565b806307880b7f146102c4578063169e02fc1461030657806316c38b3c1461034457806317fd1d8014610370576102bf565b366102bf5760645460ff16156102af57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b33346102bb8282610ba9565b5050005b600080fd5b3480156102d057600080fd5b50610304600480360360208110156102e757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610d13565b005b34801561031257600080fd5b506103306004803603602081101561032957600080fd5b5035610e10565b604080519115158252519081900360200190f35b34801561035057600080fd5b506103046004803603602081101561036757600080fd5b50351515611220565b34801561037c57600080fd5b5061039a6004803603602081101561039357600080fd5b50356112b4565b60408051918252519081900360200190f35b3480156103b857600080fd5b506103046112d2565b6103306113d8565b3480156103d557600080fd5b506103de611463565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b34801561041357600080fd5b506103de61147f565b34801561042857600080fd5b506103306004803603606081101561043f57600080fd5b8135919081019060408101602082013564010000000081111561046157600080fd5b82018360208201111561047357600080fd5b8035906020019184602083028401116401000000008311171561049557600080fd5b9193909290916020810190356401000000008111156104b357600080fd5b8201836020820111156104c557600080fd5b803590602001918460208302840111640100000000831117156104e757600080fd5b50909250905061149b565b3480156104fe57600080fd5b5061039a6004803603602081101561051557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661181d565b34801561053e57600080fd5b506103de611ca9565b34801561055357600080fd5b506103306004803603608081101561056a57600080fd5b5080359073ffffffffffffffffffffffffffffffffffffffff60208201351690604081013590606001351515611cc5565b3480156105a757600080fd5b50610304600480360360208110156105be57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611d51565b3480156105e757600080fd5b5061033061256f565b3480156105fc57600080fd5b5061039a612578565b34801561061157600080fd5b5061039a61259c565b34801561062657600080fd5b506103de6125a2565b34801561063b57600080fd5b5061039a6125be565b34801561065057600080fd5b506106846004803603602081101561066757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612904565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156106c85781810151838201526020016106b0565b50505050905001838103825284818151815260200191508051906020019060200280838360005b838110156107075781810151838201526020016106ef565b5050505090500194505050505060405180910390f35b34801561072957600080fd5b506103046004803603602081101561074057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612b7a565b34801561076957600080fd5b506103046004803603602081101561078057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612c98565b3480156107a957600080fd5b506107c7600480360360208110156107c057600080fd5b5035612eb3565b6040805173ffffffffffffffffffffffffffffffffffffffff909516855260208501939093528383019190915215156060830152519081900360800190f35b34801561081257600080fd5b506103de612ef4565b34801561082757600080fd5b5061039a6004803603604081101561083e57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135612f10565b34801561086d57600080fd5b506103306004803603602081101561088457600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16612f2d565b3480156108ad57600080fd5b50610330600480360360408110156108c457600080fd5b5080359060200135613137565b3480156108dd57600080fd5b50610330600480360360408110156108f457600080fd5b50803590602001356136f6565b34801561090d57600080fd5b5061039a6004803603604081101561092457600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135613781565b34801561095357600080fd5b506103de613970565b34801561096857600080fd5b506103046004803603602081101561097f57600080fd5b503561398c565b34801561099257600080fd5b5061039a600480360360208110156109a957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16613a1d565b3480156109d257600080fd5b50610330600480360360808110156109e957600080fd5b810190602081018135640100000000811115610a0457600080fd5b820183602082011115610a1657600080fd5b80359060200191846020830284011164010000000083111715610a3857600080fd5b919390929091602081019035640100000000811115610a5657600080fd5b820183602082011115610a6857600080fd5b80359060200191846020830284011164010000000083111715610a8a57600080fd5b919390929091602081019035640100000000811115610aa857600080fd5b820183602082011115610aba57600080fd5b80359060200191846020830284011164010000000083111715610adc57600080fd5b919390929091602081019035640100000000811115610afa57600080fd5b820183602082011115610b0c57600080fd5b80359060200191846020830284011164010000000083111715610b2e57600080fd5b509092509050613c28565b348015610b4557600080fd5b506103de613e79565b348015610b5a57600080fd5b5061039a613e9b565b348015610b6f57600080fd5b5061039a60048036036040811015610b8657600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135613ebf565b60008111610c1857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f45544820616d6f756e74206e656564206d6f7265207468616e207a65726f0000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152609e602090815260408083207f45544800000000000000000000000000000000000000000000000000000000008452909152902054610c739082613fea565b73ffffffffffffffffffffffffffffffffffffffff83166000818152609e602090815260408083207f455448000000000000000000000000000000000000000000000000000000000080855290835292819020859055805193845290830191909152818101849052606082019290925290517fe25398ee94a2ec2dde5992b338a76ddd3a7af4d596cf2d00feba7770b31de2999181900360800190a15050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314610d89576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526043815260200180614d056043913960600191505060405180910390fd5b6001805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831617928390556040805192821680845293909116602083015280517f7f730391c4f0fa1bea34bcb9bff8c30a079b21a0359759160cb990648ab84c729281900390910190a15050565b60645460009060ff1615610e8557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b336000818152609e602090815260408083207f45544800000000000000000000000000000000000000000000000000000000008452909152902054831115610f18576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180614ce26023913960400191505060405180910390fd5b60008311610f71576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180614cbf6023913960400191505060405180910390fd5b6000610f7c82613a1d565b609654604080517f31d98b3f0000000000000000000000000000000000000000000000000000000081527f4554480000000000000000000000000000000000000000000000000000000000600482015290519293506000926110479273ffffffffffffffffffffffffffffffffffffffff16916331d98b3f916024808301926020929190829003018186803b15801561101457600080fd5b505afa158015611028573d6000803e3d6000fd5b505050506040513d602081101561103e57600080fd5b5051839061405e565b9050808511156110a2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526037815260200180614d486037913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000908152609e602090815260408083207f455448000000000000000000000000000000000000000000000000000000000084529091529020546110fd908661407c565b73ffffffffffffffffffffffffffffffffffffffff84166000818152609e602090815260408083207f45544800000000000000000000000000000000000000000000000000000000008452909152808220939093559151909187156108fc02918891818181858888f1935050505015801561117c573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff83166000818152609e602090815260408083207f455448000000000000000000000000000000000000000000000000000000000080855290835292819020548151948552918401929092528282018890526060830152517ffa659da0063f4e5cf39c3b6dae863e789ab69f82e82925c28cae633a81b2b65d9181900360800190a1600193505050505b919050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314611296576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526043815260200180614d056043913960600191505060405180910390fd5b80156112a9576112a46140be565b6112b1565b6112b16141ae565b50565b609d81815481106112c157fe5b600091825260209091200154905081565b60015473ffffffffffffffffffffffffffffffffffffffff163314611342576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526033815260200180614c1a6033913960400191505060405180910390fd5b6000805460015473ffffffffffffffffffffffffffffffffffffffff908116620100009081027fffffffffffffffffffff0000000000000000000000000000000000000000ffff8416179384905560408051938290048316808552919094049091166020830152825190927f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f928290030190a150565b60645460009060ff161561144d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b33346114598282610ba9565b6001925050505b90565b60995473ffffffffffffffffffffffffffffffffffffffff1681565b60975473ffffffffffffffffffffffffffffffffffffffff1681565b6000805462010000900473ffffffffffffffffffffffffffffffffffffffff163314611512576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526043815260200180614d056043913960600191505060405180910390fd5b6000868152609c60205260409020546115409073ffffffffffffffffffffffffffffffffffffffff16614270565b6115ab57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f496e76616c696420746f6b656e2073796d626f6c000000000000000000000000604482015290519081900360640190fd5b6000868152609c60205260409020600381015460ff161561162d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5468697320746f6b656e20697320636c6f736564000000000000000000000000604482015290519081900360640190fd5b84831461169b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4c656e677468206d69736d617463680000000000000000000000000000000000604482015290519081900360640190fd5b60005b838110156118125760008787838181106116b457fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff16905060008686848181106116e157fe5b90506020020135905061175081609e60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008d815260200190815260200160002060000154613fea90919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff83166000908152609e602090815260408083208e845290915290205560028401546117909082613fea565b600285015573ffffffffffffffffffffffffffffffffffffffff82166000818152609e602090815260408083208e84528252918290205482519384529083018d90528282018490526060830152517fe25398ee94a2ec2dde5992b338a76ddd3a7af4d596cf2d00feba7770b31de2999181900360800190a1505060010161169e565b505095945050505050565b6000805b609d54811015611b29576000609d828154811061183a57fe5b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff87168352609e8252604080842082855290925291205490915015611b2057807f4c494e41000000000000000000000000000000000000000000000000000000001415611a3957609a54604080517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152915160009361197d9316916370a08231916024808301926020929190829003018186803b15801561191a57600080fd5b505afa15801561192e573d6000803e3d6000fd5b505050506040513d602081101561194457600080fd5b505173ffffffffffffffffffffffffffffffffffffffff87166000908152609e6020908152604080832087845290915290205490613fea565b609654604080517f31d98b3f000000000000000000000000000000000000000000000000000000008152600481018690529051929350611a3192611a2a9273ffffffffffffffffffffffffffffffffffffffff16916331d98b3f916024808301926020929190829003018186803b1580156119f757600080fd5b505afa158015611a0b573d6000803e3d6000fd5b505050506040513d6020811015611a2157600080fd5b50518390614276565b8590613fea565b935050611b20565b609654604080517f31d98b3f000000000000000000000000000000000000000000000000000000008152600481018490529051611b1d92611b169273ffffffffffffffffffffffffffffffffffffffff909116916331d98b3f91602480820192602092909190829003018186803b158015611ab357600080fd5b505afa158015611ac7573d6000803e3d6000fd5b505050506040513d6020811015611add57600080fd5b505173ffffffffffffffffffffffffffffffffffffffff87166000908152609e6020908152604080832087845290915290205490614276565b8490613fea565b92505b50600101611821565b5073ffffffffffffffffffffffffffffffffffffffff82166000908152609e602090815260408083207f455448000000000000000000000000000000000000000000000000000000000084529091529020541561121b57609654604080517f31d98b3f0000000000000000000000000000000000000000000000000000000081527f455448000000000000000000000000000000000000000000000000000000000060048201529051611ca392611c9c9273ffffffffffffffffffffffffffffffffffffffff909116916331d98b3f91602480820192602092909190829003018186803b158015611c1957600080fd5b505afa158015611c2d573d6000803e3d6000fd5b505050506040513d6020811015611c4357600080fd5b505173ffffffffffffffffffffffffffffffffffffffff85166000908152609e602090815260408083207f4554480000000000000000000000000000000000000000000000000000000000845290915290205490614276565b8290613fea565b92915050565b60985473ffffffffffffffffffffffffffffffffffffffff1681565b6000805462010000900473ffffffffffffffffffffffffffffffffffffffff163314611d3c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526043815260200180614d056043913960600191505060405180910390fd5b611d488585858561429a565b95945050505050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff163314611dc7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526043815260200180614d056043913960600191505060405180910390fd5b604080517f768911da0000000000000000000000000000000000000000000000000000000081527f4c6e507269636573000000000000000000000000000000000000000000000000600482015260248101829052601a60448201527f4c6e5072696365732061646472657373206e6f742076616c69640000000000006064820152905173ffffffffffffffffffffffffffffffffffffffff83169163768911da916084808301926020929190829003018186803b158015611e8757600080fd5b505afa158015611e9b573d6000803e3d6000fd5b505050506040513d6020811015611eb157600080fd5b5051609680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055604080517f768911da0000000000000000000000000000000000000000000000000000000081527f4c6e4465627453797374656d0000000000000000000000000000000000000000600482015260248101829052601e60448201527f4c6e4465627453797374656d2061646472657373206e6f742076616c69640000606482015290519183169163768911da91608480820192602092909190829003018186803b158015611fa157600080fd5b505afa158015611fb5573d6000803e3d6000fd5b505050506040513d6020811015611fcb57600080fd5b5051609780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055604080517f768911da0000000000000000000000000000000000000000000000000000000081527f4c6e4275696c644275726e53797374656d00000000000000000000000000000060048201908152602482019283526023604483018190529385169363768911da93919260640190614c9c823960400191505060206040518083038186803b1580156120a057600080fd5b505afa1580156120b4573d6000803e3d6000fd5b505050506040513d60208110156120ca57600080fd5b5051609880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055604080517f768911da0000000000000000000000000000000000000000000000000000000081527f4c6e436f6e666967000000000000000000000000000000000000000000000000600482015260248101829052601a60448201527f4c6e436f6e6669672061646472657373206e6f742076616c6964000000000000606482015290519183169163768911da91608480820192602092909190829003018186803b1580156121ba57600080fd5b505afa1580156121ce573d6000803e3d6000fd5b505050506040513d60208110156121e457600080fd5b5051609980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055604080517f768911da0000000000000000000000000000000000000000000000000000000081527f4c6e5265776172644c6f636b65720000000000000000000000000000000000006004820152602481018290526020604482018190527f4c6e5265776172644c6f636b65722061646472657373206e6f742076616c6964606483015291519284169263768911da92608480840193919291829003018186803b1580156122d357600080fd5b505afa1580156122e7573d6000803e3d6000fd5b505050506040513d60208110156122fd57600080fd5b5051609a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055609654604080517f4c6e507269636573000000000000000000000000000000000000000000000000815291909216602082015281517f17b158864f8c520aff3282c940ec6a731d26235b9b00b651c0dd1dafb3170f5f929181900390910190a1609754604080517f4c6e4465627453797374656d0000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216602083015280517f17b158864f8c520aff3282c940ec6a731d26235b9b00b651c0dd1dafb3170f5f9281900390910190a1609854604080517f4c6e4275696c644275726e53797374656d000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216602083015280517f17b158864f8c520aff3282c940ec6a731d26235b9b00b651c0dd1dafb3170f5f9281900390910190a1609954604080517f4c6e436f6e666967000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216602083015280517f17b158864f8c520aff3282c940ec6a731d26235b9b00b651c0dd1dafb3170f5f9281900390910190a1609a54604080517f4c6e5265776172644c6f636b6572000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216602083015280517f17b158864f8c520aff3282c940ec6a731d26235b9b00b651c0dd1dafb3170f5f9281900390910190a150565b60645460ff1690565b7f455448000000000000000000000000000000000000000000000000000000000081565b609b5481565b60015473ffffffffffffffffffffffffffffffffffffffff1681565b6000805b609d5481101561282c576000609d82815481106125db57fe5b906000526020600020015490506000609c600083815260200190815260200160002060020154111561282357807f4c494e410000000000000000000000000000000000000000000000000000000014156127625760006126e0609a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16634bcdd1746040518163ffffffff1660e01b815260040160206040518083038186803b15801561269c57600080fd5b505afa1580156126b0573d6000803e3d6000fd5b505050506040513d60208110156126c657600080fd5b50516000848152609c602052604090206002015490613fea565b609654604080517f31d98b3f00000000000000000000000000000000000000000000000000000000815260048101869052905192935061275a92611a2a9273ffffffffffffffffffffffffffffffffffffffff16916331d98b3f916024808301926020929190829003018186803b1580156119f757600080fd5b935050612823565b609654604080517f31d98b3f00000000000000000000000000000000000000000000000000000000815260048101849052905161282092611b169273ffffffffffffffffffffffffffffffffffffffff909116916331d98b3f91602480820192602092909190829003018186803b1580156127dc57600080fd5b505afa1580156127f0573d6000803e3d6000fd5b505050506040513d602081101561280657600080fd5b50516000848152609c602052604090206002015490614276565b92505b506001016125c2565b50471561146057609654604080517f31d98b3f0000000000000000000000000000000000000000000000000000000081527f4554480000000000000000000000000000000000000000000000000000000000600482015290516128ff92611c9c9273ffffffffffffffffffffffffffffffffffffffff909116916331d98b3f91602480820192602092909190829003018186803b1580156128cc57600080fd5b505afa1580156128e0573d6000803e3d6000fd5b505050506040513d60208110156128f657600080fd5b50514790614276565b905090565b6060806060609d8054905060010167ffffffffffffffff8111801561292857600080fd5b50604051908082528060200260200182016040528015612952578160200160208202803683370190505b50609d5490915060609060010167ffffffffffffffff8111801561297557600080fd5b5060405190808252806020026020018201604052801561299f578160200160208202803683370190505b5090506000805b609d54811015612a72576000609d82815481106129bf57fe5b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8b168352609e8252604080842082855290925291205490915015612a695780858481518110612a0d57fe5b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff89166000908152609e8252604080822084835290925220548451859085908110612a5757fe5b60209081029190910101526001909201915b506001016129a6565b5073ffffffffffffffffffffffffffffffffffffffff86166000908152609e602090815260408083207f4554480000000000000000000000000000000000000000000000000000000000845290915290205415612b6f577f4554480000000000000000000000000000000000000000000000000000000000838281518110612af657fe5b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff87166000908152609e825260408082207f4554480000000000000000000000000000000000000000000000000000000000835290925220548251839083908110612b6057fe5b60209081029190910101526001015b509092509050915091565b600054610100900460ff1680612b935750612b93614681565b80612ba1575060005460ff16155b612bf6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180614c4d602e913960400191505060405180910390fd5b600054610100900460ff16158015612c5c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b612c6582612c98565b8015612c9457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555b5050565b600054610100900460ff1680612cb15750612cb1614681565b80612cbf575060005460ff16155b612d14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180614c4d602e913960400191505060405180910390fd5b600054610100900460ff16158015612d7a57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff909116610100171660011790555b73ffffffffffffffffffffffffffffffffffffffff8216612dfc57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4c6e41646d696e5570677261646561626c653a207a65726f2061646472657373604482015290519081900360640190fd5b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff851690810291909117825560408051928352602083019190915280517f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f9281900390910190a18015612c9457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555050565b609c60205260009081526040902080546001820154600283015460039093015473ffffffffffffffffffffffffffffffffffffffff90921692909160ff1684565b609a5473ffffffffffffffffffffffffffffffffffffffff1681565b609e60209081526000928352604080842090915290825290205481565b609754604080517f1882d09000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015282516000948594921692631882d090926024808301939192829003018186803b158015612fa057600080fd5b505afa158015612fb4573d6000803e3d6000fd5b505050506040513d6040811015612fca57600080fd5b5051905080612fdd57600191505061121b565b609954604080517f4d6daf04000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163bd02d0f5918391634d6daf04916004808301926020929190829003018186803b15801561305057600080fd5b505afa158015613064573d6000803e3d6000fd5b505050506040513d602081101561307a57600080fd5b5051604080517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526004810192909252516024808301926020929190829003018186803b1580156130d157600080fd5b505afa1580156130e5573d6000803e3d6000fd5b505050506040513d60208110156130fb57600080fd5b50519050600061310a8561181d565b90508061311d576000935050505061121b565b6000613129848361405e565b929092111595945050505050565b60645460009060ff16156131ac57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b6000838152609c60205260409020546131da9073ffffffffffffffffffffffffffffffffffffffff16614270565b61324557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f496e76616c696420746f6b656e2073796d626f6c000000000000000000000000604482015290519081900360640190fd5b6000838152609c60205260409020600181015483116132c557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f436f6c6c61746572616c20616d6f756e7420746f6f20736d616c6c0000000000604482015290519081900360640190fd5b600381015460ff161561333957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5468697320746f6b656e20697320636c6f736564000000000000000000000000604482015290519081900360640190fd5b6000848152609c60209081526040918290205482517f70a082310000000000000000000000000000000000000000000000000000000081523360048201819052935173ffffffffffffffffffffffffffffffffffffffff90921692879284926370a08231926024808301939192829003018186803b1580156133ba57600080fd5b505afa1580156133ce573d6000803e3d6000fd5b505050506040513d60208110156133e457600080fd5b5051101561345357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e73756666696369656e742062616c616e6365000000000000000000000000604482015290519081900360640190fd5b604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301523060248301529151879284169163dd62ed3e916044808301926020929190829003018186803b1580156134c957600080fd5b505afa1580156134dd573d6000803e3d6000fd5b505050506040513d60208110156134f357600080fd5b5051101561354c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526030815260200180614bea6030913960400191505060405180910390fd5b604080517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152306024830152604482018890529151918316916323b872dd916064808201926020929091908290030181600087803b1580156135cb57600080fd5b505af11580156135df573d6000803e3d6000fd5b505050506040513d60208110156135f557600080fd5b505073ffffffffffffffffffffffffffffffffffffffff82166000908152609e602090815260408083208984529091529020546136329086613fea565b73ffffffffffffffffffffffffffffffffffffffff83166000908152609e602090815260408083208a845290915290205560028301546136729086613fea565b600284015573ffffffffffffffffffffffffffffffffffffffff82166000818152609e602090815260408083208a84528252918290205482519384529083018990528282018890526060830152517fe25398ee94a2ec2dde5992b338a76ddd3a7af4d596cf2d00feba7770b31de2999181900360800190a150600195945050505050565b60645460009060ff161561376b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b33613777818585614687565b5060019392505050565b60008061378d84613a1d565b609654604080517f31d98b3f0000000000000000000000000000000000000000000000000000000081526004810187905290519293506000926138069273ffffffffffffffffffffffffffffffffffffffff16916331d98b3f916024808301926020929190829003018186803b15801561101457600080fd5b73ffffffffffffffffffffffffffffffffffffffff86166000908152609e60209081526040808320888452909152902054909150811115613874575073ffffffffffffffffffffffffffffffffffffffff84166000908152609e602090815260408083208684529091529020545b837f4c494e4100000000000000000000000000000000000000000000000000000000146138a4579150611ca39050565b609a54604080517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152915160009392909216916370a0823191602480820192602092909190829003018186803b15801561391b57600080fd5b505afa15801561392f573d6000803e3d6000fd5b505050506040513d602081101561394557600080fd5b5051905080821161395c5760009350505050611ca3565b613966828261407c565b9695505050505050565b60965473ffffffffffffffffffffffffffffffffffffffff1681565b60645460ff16156139fe57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b336000613a0b8284613781565b9050613a18828483614687565b505050565b600080613a298361181d565b609754604080517f1882d09000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301528251949550600094931692631882d09092602480840193919291829003018186803b158015613a9e57600080fd5b505afa158015613ab2573d6000803e3d6000fd5b505050506040513d6040811015613ac857600080fd5b5051905080613ad95750905061121b565b609954604080517f4d6daf04000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163bd02d0f5918391634d6daf04916004808301926020929190829003018186803b158015613b4c57600080fd5b505afa158015613b60573d6000803e3d6000fd5b505050506040513d6020811015613b7657600080fd5b5051604080517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526004810192909252516024808301926020929190829003018186803b158015613bcd57600080fd5b505afa158015613be1573d6000803e3d6000fd5b505050506040513d6020811015613bf757600080fd5b505190506000613c07838361405e565b905080841015613c1e57600094505050505061121b565b613966848261407c565b6000805462010000900473ffffffffffffffffffffffffffffffffffffffff163314613c9f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526043815260200180614d056043913960600191505060405180910390fd5b878614613d0d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6c656e677468206f66206172726179206e6f7420657100000000000000000000604482015290519081900360640190fd5b878414613d7b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6c656e677468206f66206172726179206e6f7420657100000000000000000000604482015290519081900360640190fd5b878214613de957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f6c656e677468206f66206172726179206e6f7420657100000000000000000000604482015290519081900360640190fd5b60005b88811015613e6957613e608a8a83818110613e0357fe5b90506020020135898984818110613e1657fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff16888885818110613e3f57fe5b90506020020135878786818110613e5257fe5b90506020020135151561429a565b50600101613dec565b5060019998505050505050505050565b60005462010000900473ffffffffffffffffffffffffffffffffffffffff1681565b7f4c494e410000000000000000000000000000000000000000000000000000000081565b6000817f4c494e410000000000000000000000000000000000000000000000000000000014613f1f575073ffffffffffffffffffffffffffffffffffffffff82166000908152609e60209081526040808320848452909152902054611ca3565b73ffffffffffffffffffffffffffffffffffffffff8084166000818152609e6020908152604080832087845282529182902054609a5483517f70a0823100000000000000000000000000000000000000000000000000000000815260048101959095529251613fe395919493909116926370a08231926024808301939192829003018186803b158015613fb157600080fd5b505afa158015613fc5573d6000803e3d6000fd5b505050506040513d6020811015613fdb57600080fd5b505190613fea565b9392505050565b600082820183811015613fe357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000613fe38261407685670de0b6b3a7640000614a00565b90614a73565b6000613fe383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614ab5565b60645460ff161561413057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015290519081900360640190fd5b606480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258614184614b66565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190a1565b60645460ff1661421f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015290519081900360640190fd5b606480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa614184614b66565b3b151590565b6000670de0b6b3a764000061428b8484614a00565b8161429257fe5b049392505050565b600084811a60f81b7fff000000000000000000000000000000000000000000000000000000000000001661432f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f73796d626f6c2063616e6e6f7420656d70747900000000000000000000000000604482015290519081900360640190fd5b7f45544800000000000000000000000000000000000000000000000000000000008514156143be57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f45544820697320757365642062792073797374656d0000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff841661444057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f746f6b656e20616464726573732063616e6e6f74207a65726f00000000000000604482015290519081900360640190fd5b61445f8473ffffffffffffffffffffffffffffffffffffffff16614270565b6144ca57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f746f6b656e2061646472657373206973206e6f74206120636f6e747261637400604482015290519081900360640190fd5b6000858152609c602052604090205473ffffffffffffffffffffffffffffffffffffffff1661452957609d80546001810182556000919091527fd26e832454299e9fabb89e0e5fffdc046d4e14431bc1bf607ffb2e8a1ddecf7b018590555b6000609c600087815260200190815260200160002060020154905060405180608001604052808673ffffffffffffffffffffffffffffffffffffffff168152602001858152602001828152602001841515815250609c600088815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550602082015181600101556040820151816002015560608201518160030160006101000a81548160ff0219169083151502179055509050507fb8ccd92c8fb24731fb4c076a82ecc0f1ff41af213ec928f550aa42fa8e5aee8c86868686604051808581526020018473ffffffffffffffffffffffffffffffffffffffff168152602001838152602001821515815260200194505050505060405180910390a150600195945050505050565b303b1590565b73ffffffffffffffffffffffffffffffffffffffff83166000908152609e60209081526040808320858452909152902054811115614710576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180614ce26023913960400191505060405180910390fd5b60008111614769576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180614cbf6023913960400191505060405180910390fd5b600061477484613a1d565b609654604080517f31d98b3f0000000000000000000000000000000000000000000000000000000081526004810187905290519293506000926147ed9273ffffffffffffffffffffffffffffffffffffffff16916331d98b3f916024808301926020929190829003018186803b15801561101457600080fd5b905080831115614848576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526037815260200180614d486037913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff85166000908152609e60209081526040808320878452909152902054614883908461407c565b73ffffffffffffffffffffffffffffffffffffffff86166000908152609e60209081526040808320888452825280832093909355609c90522060028101546148cb908561407c565b60028201556000858152609c602090815260408083205481517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8b81166004830152602482018a90529251929091169363a9059cbb9360448084019491939192918390030190829087803b15801561495957600080fd5b505af115801561496d573d6000803e3d6000fd5b505050506040513d602081101561498357600080fd5b505073ffffffffffffffffffffffffffffffffffffffff86166000818152609e602090815260408083208984528252918290205482519384529083018890528282018790526060830152517ffa659da0063f4e5cf39c3b6dae863e789ab69f82e82925c28cae633a81b2b65d9181900360800190a1505050505050565b600082614a0f57506000611ca3565b82820282848281614a1c57fe5b0414613fe3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526021815260200180614c7b6021913960400191505060405180910390fd5b6000613fe383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614b6a565b60008184841115614b5e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015614b23578181015183820152602001614b0b565b50505050905090810190601f168015614b505780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b3390565b60008183614bd3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201818152835160248401528351909283926044909101919085019080838360008315614b23578181015183820152602001614b0b565b506000838581614bdf57fe5b049594505050505056fe696e73756666696369656e7420616c6c6f77616e63652c206e65656420617070726f7665206d6f726520616d6f756e744c6e41646d696e5570677261646561626c653a206f6e6c792063616e6469646174652063616e206265636f6d652061646d696e496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774c6e4275696c644275726e53797374656d2061646472657373206e6f742076616c696452656465656d20616d6f756e74206e656564206c6172676572207468616e207a65726f43616e206e6f742072656465656d206d6f7265207468616e20636f6c6c61746572616c4c6e41646d696e5570677261646561626c653a206f6e6c792074686520636f6e74726163742061646d696e2063616e20706572666f726d207468697320616374696f6e42656361757365206c6f77657220636f6c6c61746572616c20726174696f2c2063616e206e6f742072656465656d20746f6f206d756368a26469706673582212200e0c79094e6fec2fadb511d661f8577099b7e4a9aef257bda9930a8cc70e72f864736f6c634300060c0033
Deployed Bytecode Sourcemap
112146:16282:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;29982:7;;;;29981:8;29973:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;126387:10:::1;126428:9;126448:31;126387:10:::0;126428:9;126448:14:::1;:31::i;:::-;30021:1;;112146:16282:::0;;;;;12754:184;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;12754:184:0;;;;:::i;:::-;;127142:877;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;127142:877:0;;:::i;:::-;;;;;;;;;;;;;;;;;;113651:161;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;113651:161:0;;;;:::i;113159:28::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;113159:28:0;;:::i;:::-;;;;;;;;;;;;;;;;12946:236;;;;;;;;;;;;;:::i;126915:219::-;;;:::i;112580:23::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;112496:30;;;;;;;;;;;;;:::i;120710:942::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;120710:942:0;;-1:-1:-1;120710:942:0;-1:-1:-1;120710:942:0;:::i;118150:1063::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;118150:1063:0;;;;:::i;112533:40::-;;;;;;;;;;;;;:::i;116098:266::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;116098:266:0;;;;;;;;;;;;;;;;;;;;;:::i;113884:1144::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;113884:1144:0;;;;:::i;29664:78::-;;;;;;;;;;;;;:::i;112654:44::-;;;;;;;;;;;;;:::i;112824:23::-;;;;;;;;;;;;;:::i;12486:24::-;;;;;;;;;;;;;:::i;117125:1017::-;;;;;;;;;;;;;:::i;119613:935::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;119613:935:0;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;113521:122;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;113521:122:0;;;;:::i;12519:227::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;12519:227:0;;;;:::i;113105:47::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;113105:47:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;112610:35;;;;;;;;;;;;;:::i;113368:80::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;113368:80:0;;;;;;;;;:::i;122780:571::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;122780:571:0;;;;:::i;121681:1091::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;121681:1091:0;;;;;;;:::i;126114:198::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;126114:198:0;;;;;;;:::i;124071:676::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;124071:676:0;;;;;;;;;:::i;112462:27::-;;;;;;;;;;;;;:::i;124755:212::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;124755:212:0;;:::i;123450:613::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;123450:613:0;;;;:::i;116372:664::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;116372:664:0;;-1:-1:-1;116372:664:0;-1:-1:-1;116372:664:0;:::i;12459:20::-;;;;;;;;;;;;;:::i;112705:46::-;;;;;;;;;;;;;:::i;119221:325::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;119221:325:0;;;;;;;;;:::i;126495:383::-;126592:1;126580:9;:13;126572:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;126693:24;;;;;;;:18;:24;;;;;;;;126718:12;126693:38;;;;;;;:49;:64;;126747:9;126693:53;:64::i;:::-;126641:24;;;;;;;:18;:24;;;;;;;;126666:12;126641:38;;;;;;;;;;:116;;;126775:95;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;126495:383;;:::o;12754:184::-;13243:5;;;;;;;13229:10;:19;13220:101;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12840:9:::1;::::0;;::::1;12860:22:::0;;::::1;::::0;;::::1;;::::0;;;;12898:32:::1;::::0;;12840:9;;::::1;12898:32:::0;;;12920:9;;;::::1;12898:32;::::0;::::1;::::0;;;::::1;::::0;;;;;;;;::::1;13332:1;12754:184:::0;:::o;127142:877::-;29982:7;;127210:4;;29982:7;;29981:8;29973:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;127250:10:::1;127227:20;127290:24:::0;;;:18:::1;:24;::::0;;;;;;;127315:12:::1;127290:38:::0;;;;;;;:49;127279:60;::::1;;127271:108;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;127408:1;127398:7;:11;127390:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;127462:26;127491:24;127510:4;127491:18;:24::i;:::-;127581:11;::::0;:34:::1;::::0;;;;;127602:12:::1;127581:34;::::0;::::1;::::0;;;127462:53;;-1:-1:-1;127528:17:0::1;::::0;127548:68:::1;::::0;127581:11:::1;;::::0;:20:::1;::::0;:34;;;;;::::1;::::0;;;;;;;;:11;:34;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;127581:34:0;127548:18;;:32:::1;:68::i;:::-;127528:88;;127646:9;127635:7;:20;;127627:88;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;127780:24;::::0;::::1;;::::0;;;:18:::1;:24;::::0;;;;;;;127805:12:::1;127780:38:::0;;;;;;;:49;:62:::1;::::0;127834:7;127780:53:::1;:62::i;:::-;127728:24;::::0;::::1;;::::0;;;:18:::1;:24;::::0;;;;;;;127753:12:::1;127728:38:::0;;;;;;;;:114;;;;127853:22;;127728:24;;127853:22;::::1;;;::::0;127867:7;;127853:22;127728:24;127853:22;127867:7;127728:24;127853:22;::::1;;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;127939:24:0::1;::::0;::::1;;::::0;;;:18:::1;:24;::::0;;;;;;;127916:12:::1;127939:38:::0;;;;;;;;;;:49;127893:96;;;;;;;::::1;::::0;;;;;;;;;;;;;;;::::1;::::0;;;;;;;::::1;128007:4;128000:11;;;;;30021:1;127142:877:::0;;;:::o;113651:161::-;13243:5;;;;;;;13229:10;:19;13220:101;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;113718:7:::1;113714:91;;;113742:8;:6;:8::i;:::-;113714:91;;;113783:10;:8;:10::i;:::-;113651:161:::0;:::o;113159:28::-;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;113159:28:0;:::o;12946:236::-;13011:9;;;;12997:10;:23;12989:87;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13087:11;13101:5;;13125:9;;13101:5;13125:9;;;13101:5;13117:17;;;;;;;;;;;13150:24;;;13101:5;;;;;;13150:24;;;13168:5;;;;;;;13150:24;;;;;;13101:5;;13150:24;;;;;;;;12946:236;:::o;126915:219::-;29982:7;;126980:4;;29982:7;;29981:8;29973:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;127012:10:::1;127053:9;127073:31;127012:10:::0;127053:9;127073:14:::1;:31::i;:::-;127122:4;127115:11;;;;30021:1;126915:219:::0;:::o;112580:23::-;;;;;;:::o;112496:30::-;;;;;;:::o;120710:942::-;120874:4;13243:5;;;;;;;13229:10;:19;13220:101;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;120899:21:::1;::::0;;;:10:::1;:21;::::0;;;;:31;:44:::1;::::0;:31:::1;;:42;:44::i;:::-;120891:77;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;120979:27;121009:21:::0;;;:10:::1;:21;::::0;;;;121049:16:::1;::::0;::::1;::::0;::::1;;:25;121041:58;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;121118:32:::0;;::::1;121110:60;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;121188:11;121183:462;121205:21:::0;;::::1;121183:462;;;121250:12;121265:6;;121272:3;121265:11;;;;;;;;;;;;;;;121250:26;;121291:14;121308:8;;121317:3;121308:13;;;;;;;;;;;;;121291:30;;121387:58;121438:6;121387:18;:24;121406:4;121387:24;;;;;;;;;;;;;;;:35;121412:9;121387:35;;;;;;;;;;;:46;;;:50;;:58;;;;:::i;:::-;121338:24;::::0;::::1;;::::0;;;:18:::1;:24;::::0;;;;;;;:35;;;;;;;;:107;121488:25:::1;::::0;::::1;::::0;:37:::1;::::0;121518:6;121488:29:::1;:37::i;:::-;121460:25;::::0;::::1;:65:::0;121586:24:::1;::::0;::::1;;::::0;;;:18:::1;:24;::::0;;;;;;;:35;;;;;;;;;:46;121547:86;;;;;;;::::1;::::0;;;;;;;;;;;;;;::::1;::::0;;;;;;;::::1;-1:-1:-1::0;;121228:5:0::1;;121183:462;;;;13332:1;120710:942:::0;;;;;;;:::o;118150:1063::-;118223:14;;118250:702;118274:11;:18;118270:22;;118250:702;;;118314:16;118333:11;118345:1;118333:14;;;;;;;;;;;;;;;;;;;;118366:25;;;;;:18;:25;;;;;;:35;;;;;;;;:46;118333:14;;-1:-1:-1;118366:50:0;118362:579;;118458:8;118441:13;:25;118437:489;;;118562:13;;:30;;;;;;:13;:30;;;;;;;;;118491:17;;118511:82;;118562:13;;:23;;:30;;;;;;;;;;;;;;:13;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;118562:30:0;118511:25;;;;;;;:18;118562:30;118511:25;;;;;;;:35;;;;;;;;:46;;:50;:82::i;:::-;118662:11;;:30;;;;;;;;;;;;;;118491:102;;-1:-1:-1;118625:69:0;;118636:57;;118662:11;;;:20;;:30;;;;;;;;;;;;;;:11;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;118662:30:0;118636:9;;:25;:57::i;:::-;118625:6;;:10;:69::i;:::-;118616:78;;118437:489;;;;118852:11;;:30;;;;;;;;;;;;;;118752:154;;118789:94;;118852:11;;;;;:20;;:30;;;;;;;;;;;;;;;:11;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;118852:30:0;118789:25;;;;;;;:18;118852:30;118789:25;;;;;;;:35;;;;;;;;:46;;:62;:94::i;:::-;118752:6;;:10;:154::i;:::-;118743:163;;118437:489;-1:-1:-1;118294:3:0;;118250:702;;;-1:-1:-1;118968:25:0;;;119021:1;118968:25;;;:18;:25;;;;;;;;118994:12;118968:39;;;;;;;:50;:54;118964:242;;119144:11;;:34;;;;;;119165:12;119144:34;;;;;;119048:146;;119077:102;;119144:11;;;;;:20;;:34;;;;;;;;;;;;;;;:11;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;119144:34:0;119077:25;;;;;;;:18;119144:34;119077:25;;;;;;;119103:12;119077:39;;;;;;;:50;;:66;:102::i;:::-;119048:6;;:10;:146::i;:::-;119039:155;118150:1063;-1:-1:-1;;118150:1063:0:o;112533:40::-;;;;;;:::o;116098:266::-;116270:4;13243:5;;;;;;;13229:10;:19;13220:101;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;116294:62:::1;116310:9;116321:10;116333:14;116349:6;116294:15;:62::i;:::-;116287:69:::0;116098:266;-1:-1:-1;;;;;116098:266:0:o;113884:1144::-;13243:5;;;;;;;13229:10;:19;13220:101;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;114006:79:::1;::::0;;;;;::::1;;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;::::1;::::0;;;;;;:37:::1;::::0;::::1;::::0;::::1;::::0;:79;;;;;::::1;::::0;;;;;;;;:37;:79;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;114006:79:0;113983:11:::1;:103:::0;;;::::1;;::::0;;::::1;;::::0;;114123:87:::1;::::0;;;;;::::1;;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;::::1;::::0;;;;;;:37;;::::1;::::0;::::1;::::0;:87;;;;;114006:79:::1;::::0;114123:87;;;;;;;;:37;:87;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;114123:87:0;114097:10:::1;:114:::0;;;::::1;;::::0;;::::1;;::::0;;114272:97:::1;::::0;;;;;::::1;;::::0;::::1;::::0;;;;;;;;;::::1;::::0;;;;;;:37;;::::1;::::0;::::1;::::0;:97;;;;;::::1;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;114272:97:0;114222:15:::1;:158:::0;;;::::1;;::::0;;::::1;;::::0;;114410:79:::1;::::0;;;;;::::1;;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;::::1;::::0;;;;;;:37;;::::1;::::0;::::1;::::0;:79;;;;;114272:97:::1;::::0;114410:79;;;;;;;;:37;:79;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;114410:79:0;114391:7:::1;:99:::0;;;::::1;;::::0;;::::1;;::::0;;114546:91:::1;::::0;;;;;::::1;;::::0;::::1;::::0;;;;;;;114410:79:::1;114546:91:::0;;;;;;::::1;::::0;;;;;;:37;;::::1;::::0;::::1;::::0;:91;;;;;114410:79;;114546:91;;;;;;:37;:91;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;114546:91:0;114501:13:::1;:147:::0;;;::::1;;::::0;;::::1;;::::0;;114707:11:::1;::::0;114666:54:::1;::::0;;::::1;::::0;;114707:11;;;::::1;114546:91;114666:54:::0;::::1;::::0;;;::::1;::::0;;;;;;;;;::::1;114781:10;::::0;114736:57:::1;::::0;;::::1;::::0;;114781:10:::1;::::0;;::::1;114736:57;::::0;::::1;::::0;;;::::1;::::0;;;;;;;;::::1;114859:15;::::0;114809:67:::1;::::0;;::::1;::::0;;114859:15:::1;::::0;;::::1;114809:67;::::0;::::1;::::0;;;::::1;::::0;;;;;;;;::::1;114933:7;::::0;114892:50:::1;::::0;;::::1;::::0;;114933:7:::1;::::0;;::::1;114892:50;::::0;::::1;::::0;;;::::1;::::0;;;;;;;;::::1;115005:13;::::0;114958:62:::1;::::0;;::::1;::::0;;115005:13:::1;::::0;;::::1;114958:62;::::0;::::1;::::0;;;::::1;::::0;;;;;;;;::::1;113884:1144:::0;:::o;29664:78::-;29727:7;;;;29664:78;:::o;112654:44::-;;;:::o;112824:23::-;;;;:::o;12486:24::-;;;;;;:::o;117125:1017::-;117187:14;;117214:757;117238:11;:18;117234:22;;117214:757;;;117278:16;117297:11;117309:1;117297:14;;;;;;;;;;;;;;;;117278:33;;117369:1;117330:10;:20;117341:8;117330:20;;;;;;;;;;;:36;;;:40;117326:634;;;117494:8;117477:13;:25;117473:472;;;117527:17;117547:75;117588:13;;;;;;;;;;;:31;;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;117588:33:0;117547:20;;;;:10;117588:33;117547:20;;;;:36;;;;:40;:75::i;:::-;117691:11;;:30;;;;;;;;;;;;;;117527:95;;-1:-1:-1;117654:69:0;;117665:57;;117691:11;;;:20;;:30;;;;;;;;;;;;;;:11;:30;;;;;;;;;;117654:69;117645:78;;117473:472;;;;117871:11;;:30;;;;;;;;;;;;;;117781:144;;117818:84;;117871:11;;;;;:20;;:30;;;;;;;;;;;;;;;:11;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;117871:30:0;117818:20;;;;:10;117871:30;117818:20;;;;:36;;;;:52;:84::i;117781:144::-;117772:153;;117473:472;-1:-1:-1;117258:3:0;;117214:757;;;-1:-1:-1;117987:21:0;:25;117983:152;;118087:11;;:34;;;;;;118108:12;118087:34;;;;;;118038:85;;118049:73;;118087:11;;;;;:20;;:34;;;;;;;;;;;;;;;:11;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;118087:34:0;118049:21;;:37;:73::i;118038:85::-;118029:94;;117125:1017;:::o;119613:935::-;119679:16;119697;119726:26;119769:11;:18;;;;119790:1;119769:22;119755:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;119755:37:0;-1:-1:-1;119844:11:0;:18;119726:66;;-1:-1:-1;119803:24:0;;119865:1;119844:22;119830:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;119830:37:0;;119803:64;;119878:15;119913:9;119908:355;119932:11;:18;119928:22;;119908:355;;;119972:16;119991:11;120003:1;119991:14;;;;;;;;;;;;;;;;;;;;120024:25;;;;;:18;:25;;;;;;:35;;;;;;;;:46;119991:14;;-1:-1:-1;120024:50:0;120020:232;;120116:8;120095:9;120105:7;120095:18;;;;;;;;;;;;;;;;;;:29;;;;120162:25;;;;;;;:18;:25;;;;;;:35;;;;;;;:46;120143:16;;:7;;120151;;120143:16;;;;;;;;;;;;;;;:65;120227:9;;;;;120020:232;-1:-1:-1;119952:3:0;;119908:355;;;-1:-1:-1;120277:25:0;;;120330:1;120277:25;;;:18;:25;;;;;;;;120303:12;120277:39;;;;;;;:50;:54;120273:228;;120369:12;120348:9;120358:7;120348:18;;;;;;;;;;;;;;;;;;:33;;;;120415:25;;;;;;;:18;:25;;;;;;120441:12;120415:39;;;;;;:50;120396:16;;:7;;120404;;120396:16;;;;;;;;;;;;;;;:69;120480:9;;120273:228;-1:-1:-1;120521:9:0;;-1:-1:-1;120532:7:0;-1:-1:-1;119613:935:0;;;:::o;113521:122::-;1572:13;;;;;;;;:33;;;1589:16;:14;:16::i;:::-;1572:50;;;-1:-1:-1;1610:12:0;;;;1609:13;1572:50;1564:109;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1686:19;1709:13;;;;;;1708:14;1733:101;;;;1768:13;:20;;1803:19;1768:20;;;;;;1803:19;1784:4;1803:19;;;1733:101;113602:33:::1;113628:6;113602:25;:33::i;:::-;1864:14:::0;1860:68;;;1911:5;1895:21;;;;;;1860:68;113521:122;;:::o;12519:227::-;1572:13;;;;;;;;:33;;;1589:16;:14;:16::i;:::-;1572:50;;;-1:-1:-1;1610:12:0;;;;1609:13;1572:50;1564:109;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1686:19;1709:13;;;;;;1708:14;1733:101;;;;1768:13;:20;;1803:19;1768:20;;;;;;1803:19;1784:4;1803:19;;;1733:101;12608:20:::1;::::0;::::1;12600:65;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;;;;;;;::::1;::::0;;;;;;;;;;;;;::::1;;12676:5;:14:::0;;;::::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;;;::::1;::::0;;12706:32:::1;::::0;;;;;::::1;::::0;::::1;::::0;;;;;;::::1;::::0;;;;;;;;::::1;1864:14:::0;1860:68;;;1911:5;1895:21;;;;;;12519:227;;:::o;113105:47::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;112610:35::-;;;;;;:::o;113368:80::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;122780:571::-;122889:10;;:41;;;;;;:10;:41;;;;;;;;;122846:4;;;;122889:10;;;:34;;:41;;;;;;;;;;;;:10;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;122889:41:0;;-1:-1:-1;122945:16:0;122941:60;;122985:4;122978:11;;;;;122941:60;123034:7;;123050:21;;;;;;;;123013:18;;123034:7;;;:15;;:7;;123050:19;;:21;;;;;;;;;;;;;;123034:7;123050:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;123050:21:0;123034:38;;;;;;;;;;;;;;;;;;;;;;;;123050:21;;123034:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;123034:38:0;;-1:-1:-1;123083:28:0;123114:34;123142:5;123114:27;:34::i;:::-;123083:65;-1:-1:-1;123163:25:0;123159:70;;123212:5;123205:12;;;;;;;123159:70;123239:15;123257:47;:11;123283:20;123257:25;:47::i;:::-;123322:21;;;;;;122780:571;-1:-1:-1;;;;;122780:571:0:o;121681:1091::-;29982:7;;121769:4;;29982:7;;29981:8;29973:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;121794:21:::1;::::0;;;:10:::1;:21;::::0;;;;:31;:44:::1;::::0;:31:::1;;:42;:44::i;:::-;121786:77;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;121874:27;121904:21:::0;;;:10:::1;:21;::::0;;;;121954:23:::1;::::0;::::1;::::0;121944:33;::::1;121936:73;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;122028:16;::::0;::::1;::::0;::::1;;:25;122020:58;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;122091:12;122151:21:::0;;;:10:::1;:21;::::0;;;;;;;;:31;122202:21;;;;;122106:10:::1;122202:21;::::0;::::1;::::0;;;;;122151:31:::1;::::0;;::::1;::::0;122227:7;;122151:31;;122202:15:::1;::::0;:21;;;;;122151;;122202;;;;;122151:31;122202:21;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;122202:21:0;:32:::1;;122194:65;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;122278:36;::::0;;;;;:15:::1;:36:::0;;::::1;;::::0;::::1;::::0;122308:4:::1;122278:36:::0;;;;;;122318:7;;122278:15;::::1;::::0;::::1;::::0;:36;;;;;::::1;::::0;;;;;;;;:15;:36;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;122278:36:0;:47:::1;;122270:108;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;122391:48;::::0;;;;;:18:::1;:48:::0;;::::1;;::::0;::::1;::::0;122424:4:::1;122391:48:::0;;;;;;;;;;;;:18;;::::1;::::0;::::1;::::0;:48;;;;;::::1;::::0;;;;;;;;;-1:-1:-1;122391:18:0;:48;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;-1:-1:-1::0;;122501:24:0::1;::::0;::::1;;::::0;;;:18:::1;122391:48;122501:24:::0;;;;;;;:35;;;;;;;;:46;:59:::1;::::0;122552:7;122501:50:::1;:59::i;:::-;122452:24;::::0;::::1;;::::0;;;:18:::1;:24;::::0;;;;;;;:35;;;;;;;;:108;122599:25:::1;::::0;::::1;::::0;:38:::1;::::0;122629:7;122599:29:::1;:38::i;:::-;122571:25;::::0;::::1;:66:::0;122695:24:::1;::::0;::::1;;::::0;;;:18:::1;:24;::::0;;;;;;;:35;;;;;;;;;:46;122655:87;;;;;;;::::1;::::0;;;;;;;;;;;;;;::::1;::::0;;;;;;;::::1;-1:-1:-1::0;122760:4:0::1;::::0;121681:1091;-1:-1:-1;;;;;121681:1091:0:o;126114:198::-;29982:7;;126196:4;;29982:7;;29981:8;29973:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;126228:10:::1;126249:33;126228:10:::0;126263:9;126274:7;126249::::1;:33::i;:::-;-1:-1:-1::0;126300:4:0::1;::::0;126114:198;-1:-1:-1;;;126114:198:0:o;124071:676::-;124148:7;124168:26;124197:24;124216:4;124197:18;:24::i;:::-;124285:11;;:31;;;;;;;;;;;;;;124168:53;;-1:-1:-1;124232:17:0;;124252:65;;124285:11;;;:20;;:31;;;;;;;;;;;;;;:11;:31;;;;;;;;;;124252:65;124344:24;;;;;;;:18;:24;;;;;;;;:35;;;;;;;;:46;124232:85;;-1:-1:-1;124332:58:0;;124328:149;;;-1:-1:-1;124419:24:0;;;;;;;:18;:24;;;;;;;;:35;;;;;;;;:46;124328:149;124508:9;124491:13;:26;124487:75;;124541:9;-1:-1:-1;124534:16:0;;-1:-1:-1;124534:16:0;124487:75;124593:13;;:29;;;;;;:13;:29;;;;;;;;;124572:18;;124593:13;;;;;:23;;:29;;;;;;;;;;;;;;;:13;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;124593:29:0;;-1:-1:-1;124637:23:0;;;124633:64;;124684:1;124677:8;;;;;;;124633:64;124714:25;:9;124728:10;124714:13;:25::i;:::-;124707:32;124071:676;-1:-1:-1;;;;;;124071:676:0:o;112462:27::-;;;;;;:::o;124755:212::-;29982:7;;;;29981:8;29973:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;124842:10:::1;124827:12;124883:30;124842:10:::0;124903:9;124883:13:::1;:30::i;:::-;124863:50;;124924:35;124932:4;124938:9;124949;124924:7;:35::i;:::-;30021:1;;124755:212:::0;:::o;123450:613::-;123514:7;123534:28;123565:34;123593:5;123565:27;:34::i;:::-;123638:10;;:41;;;;;;:10;:41;;;;;;;;;123534:65;;-1:-1:-1;123613:19:0;;123638:10;;;:34;;:41;;;;;;;;;;;;;:10;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;123638:41:0;;-1:-1:-1;123694:16:0;123690:76;;-1:-1:-1;123734:20:0;-1:-1:-1;123727:27:0;;123690:76;123799:7;;123815:21;;;;;;;;123778:18;;123799:7;;;:15;;:7;;123815:19;;:21;;;;;;;;;;;;;;123799:7;123815:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;123815:21:0;123799:38;;;;;;;;;;;;;;;;;;;;;;;;123815:21;;123799:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;123799:38:0;;-1:-1:-1;123848:21:0;123872:37;:11;123799:38;123872:25;:37::i;:::-;123848:61;;123947:13;123924:20;:36;123920:77;;;123984:1;123977:8;;;;;;;;123920:77;124016:39;:20;124041:13;124016:24;:39::i;116372:664::-;116590:4;13243:5;;;;;;;13229:10;:19;13220:101;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;116615:37;;::::1;116607:72;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;116698:40:::0;;::::1;116690:75;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;116784:33:::0;;::::1;116776:68;;;::::0;;::::1;::::0;;::::1;;::::0;::::1;::::0;::::1;::::0;;;;::::1;::::0;;;;;;;;;;;;;::::1;;116862:9;116857:148;116877:19:::0;;::::1;116857:148;;;116918:75;116934:8;;116943:1;116934:11;;;;;;;;;;;;;116947;;116959:1;116947:14;;;;;;;;;;;;;;;116963;;116978:1;116963:17;;;;;;;;;;;;;116982:7;;116990:1;116982:10;;;;;;;;;;;;;;;116918:15;:75::i;:::-;-1:-1:-1::0;116898:3:0::1;;116857:148;;;-1:-1:-1::0;117024:4:0::1;::::0;116372:664;-1:-1:-1;;;;;;;;;116372:664:0:o;12459:20::-;;;;;;;;;:::o;112705:46::-;;;:::o;119221:325::-;119305:7;119346:9;119329:13;:26;119325:113;;-1:-1:-1;119379:25:0;;;;;;;:18;:25;;;;;;;;:36;;;;;;;;:47;119372:54;;119325:113;119490:25;;;;;;;;:18;:25;;;;;;;;:36;;;;;;;;;:47;119455:13;;:30;;;;;;;;;;;;;;:83;;119490:47;;119455:13;;;;;:23;;:30;;;;;119490:25;;119455:30;;;;;:13;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;119455:30:0;;:34;:83::i;:::-;119448:90;119221:325;-1:-1:-1;;;119221:325:0:o;22773:181::-;22831:7;22863:5;;;22887:6;;;;22879:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20730:112;20792:4;20816:18;20832:1;20816:11;:1;19569:18;20816:5;:11::i;:::-;:15;;:18::i;23237:136::-;23295:7;23322:43;23326:1;23329;23322:43;;;;;;;;;;;;;;;;;:3;:43::i;30454:118::-;29982:7;;;;29981:8;29973:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30514:7:::1;:14:::0;;;::::1;30524:4;30514:14;::::0;;30544:20:::1;30551:12;:10;:12::i;:::-;30544:20;::::0;;::::1;::::0;;::::1;::::0;;;;;;;::::1;::::0;;::::1;30454:118::o:0;30713:120::-;30258:7;;;;30250:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30772:7:::1;:15:::0;;;::::1;::::0;;30803:22:::1;30812:12;:10;:12::i;31566:444::-:0;31946:20;31994:8;;;31566:444::o;19967:111::-;20031:4;19569:18;20055:8;:1;20061;20055:5;:8::i;:::-;:15;;;;;;;19967:111;-1:-1:-1;;;19967:111:0:o;115036:991::-;115197:4;115222:9;115197:4;115222:12;;;:17;;115214:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;115295:12;115282:9;:25;;115274:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;115352:24;;;115344:62;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;115425:23;:10;:21;;;:23::i;:::-;115417:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;115544:1;115501:21;;;:10;:21;;;;;:31;:45;:31;115497:131;;115589:11;:27;;;;;;;-1:-1:-1;115589:27:0;;;;;;;;;115497:131;115640:23;115666:10;:21;115677:9;115666:21;;;;;;;;;;;:37;;;115640:63;;115738:178;;;;;;;;115774:10;115738:178;;;;;;115814:14;115738:178;;;;115860:15;115738:178;;;;115898:6;115738:178;;;;;115714:10;:21;115725:9;115714:21;;;;;;;;;;;:202;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;115932:65;115951:9;115962:10;115974:14;115990:6;115932:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;116015:4:0;;115036:991;-1:-1:-1;;;;;115036:991:0:o;2028:626::-;2470:4;2594:17;2639:7;2028:626;:::o;124975:1011::-;125115:24;;;;;;;:18;:24;;;;;;;;:35;;;;;;;;:46;125104:57;;;125096:105;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;125230:1;125220:7;:11;125212:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;125284:26;125313:24;125332:4;125313:18;:24::i;:::-;125401:11;;:31;;;;;;;;;;;;;;125284:53;;-1:-1:-1;125348:17:0;;125368:65;;125401:11;;;:20;;:31;;;;;;;;;;;;;;:11;:31;;;;;;;;;;125368:65;125348:85;;125463:9;125452:7;:20;;125444:88;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;125594:24;;;;;;;:18;:24;;;;;;;;:35;;;;;;;;:46;:59;;125645:7;125594:50;:59::i;:::-;125545:24;;;;;;;:18;:24;;;;;;;;:35;;;;;;;;:108;;;;125696:10;:21;;;125756:25;;;;:38;;125786:7;125756:29;:38::i;:::-;125728:25;;;:66;125814:21;;;;:10;:21;;;;;;;;:31;125807:63;;;;;125814:31;125807:63;;;;;;;;;;;;;;;125814:31;;;;;125807:48;;:63;;;;;125814:21;;125807:63;;;;;;;;;;125814:31;125807:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;125931:24:0;;;;;;;:18;125807:63;125931:24;;;;;;;:35;;;;;;;;;:46;125888:90;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;124975:1011;;;;;;:::o;24161:471::-;24219:7;24464:6;24460:47;;-1:-1:-1;24494:1:0;24487:8;;24460:47;24531:5;;;24535:1;24531;:5;:1;24555:5;;;;;:10;24547:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25108:132;25166:7;25193:39;25197:1;25200;25193:39;;;;;;;;;;;;;;;;;:3;:39::i;23676:226::-;23796:7;23832:12;23824:6;;;;23816:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;23868:5:0;;;23676:226::o;28073:106::-;28161:10;28073:106;:::o;25736:312::-;25856:7;25891:12;25884:5;25876:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;25915:9;25931:1;25927;:5;;;;;;;25736:312;-1:-1:-1;;;;;25736:312:0:o
Swarm Source
ipfs://0e0c79094e6fec2fadb511d661f8577099b7e4a9aef257bda9930a8cc70e72f8
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.