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
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ExternalTokenStakeManager
Compiler Version
v0.5.16+commit.9c3226ce
Optimization Enabled:
Yes with 1000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2024-05-24 */ /* ___ _ ___ _ | .\ ___ _ _ <_> ___ | __><_>._ _ ___ ._ _ ___ ___ | _// ._>| '_>| ||___|| _> | || ' |<_> || ' |/ | '/ ._> |_| \___.|_| |_| |_| |_||_|_|<___||_|_|\_|_.\___. * PeriFinance: ExternalTokenStakeManager.sol * * Latest source (may be newer): https://github.com/perifinance/peri-finance/blob/master/contracts/ExternalTokenStakeManager.sol * Docs: Will be added in the future. * https://docs.peri.finance/contracts/source/contracts/ExternalTokenStakeManager * * Contract Dependencies: * - IAddressResolver * - MixinResolver * - Owned * Libraries: * - SafeDecimalMath * - SafeMath * * MIT License * =========== * * Copyright (c) 2024 PeriFinance * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ pragma solidity 0.5.16; // https://docs.peri.finance/contracts/source/contracts/owned contract Owned { address public owner; address public nominatedOwner; constructor(address _owner) public { require(_owner != address(0), "Owner address cannot be 0"); owner = _owner; emit OwnerChanged(address(0), _owner); } function nominateNewOwner(address _owner) external onlyOwner { nominatedOwner = _owner; emit OwnerNominated(_owner); } function acceptOwnership() external { require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership"); emit OwnerChanged(owner, nominatedOwner); owner = nominatedOwner; nominatedOwner = address(0); } modifier onlyOwner { _onlyOwner(); _; } function _onlyOwner() private view { require(msg.sender == owner, "Only the contract owner may perform this action"); } event OwnerNominated(address newOwner); event OwnerChanged(address oldOwner, address newOwner); } // https://docs.peri.finance/contracts/source/interfaces/iaddressresolver interface IAddressResolver { function getAddress(bytes32 name) external view returns (address); function getPynth(bytes32 key) external view returns (address); function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address); } // https://docs.peri.finance/contracts/source/interfaces/ipynth interface IPynth { // Views function currencyKey() external view returns (bytes32); function transferablePynths(address account) external view returns (uint); // Mutative functions function transferAndSettle(address to, uint value) external returns (bool); function transferFromAndSettle( address from, address to, uint value ) external returns (bool); // Restricted: used internally to PeriFinance function burn(address account, uint amount) external; function issue(address account, uint amount) external; } // https://docs.peri.finance/contracts/source/interfaces/iissuer interface IIssuer { // Views function anyPynthOrPERIRateIsInvalid() external view returns (bool anyRateInvalid); function availableCurrencyKeys() external view returns (bytes32[] memory); function availablePynthCount() external view returns (uint); function availablePynths(uint index) external view returns (IPynth); function canBurnPynths(address account) external view returns (bool); function collateral(address account) external view returns (uint); function collateralisationRatio(address issuer) external view returns (uint); function collateralisationRatioAndAnyRatesInvalid(address _issuer) external view returns (uint cratio, bool anyRateIsInvalid); function debtBalanceOf(address issuer, bytes32 currencyKey) external view returns (uint debtBalance); function lastIssueEvent(address account) external view returns (uint); function maxIssuablePynths(address issuer) external view returns ( uint, uint, uint ); // function externalTokenQuota( // address _account, // uint _addtionalpUSD, // uint _addtionalExToken, // bool _isIssue // ) external view returns (uint); // function debtsCollateral(address _account, bool _rateCheck) external // view // returns ( // uint, // uint, // uint // ); function getRatios(address _account, bool _checkRate) external view returns ( uint, uint, uint, uint, uint, uint ); function getTargetRatio(address account) external view returns (uint); // function getTRatioCRatio(address _account) // external // view // returns ( // uint, // uint, // uint, // uint // ); function remainingIssuablePynths(address issuer) external view returns ( uint maxIssuable, uint alreadyIssued, uint totalSystemDebt ); function pynths(bytes32 currencyKey) external view returns (IPynth); function getPynths(bytes32[] calldata currencyKeys) external view returns (IPynth[] memory); function pynthsByAddress(address pynthAddress) external view returns (bytes32); function totalIssuedPynths(bytes32 currencyKey, bool excludeEtherCollateral) external view returns (uint, bool); function transferablePeriFinanceAndAnyRateIsInvalid(address account, uint balance) external view returns (uint transferable, bool anyRateIsInvalid); function amountsToFitClaimable(address _account) external view returns (uint burnAmount, uint exTokenAmountToUnstake); // Restricted: used internally to PeriFinance function issuePynths( address _issuer, bytes32 _currencyKey, uint _issueAmount ) external; function issueMaxPynths(address _issuer) external; function issuePynthsToMaxQuota(address _issuer, bytes32 _currencyKey) external; function burnPynths( address _from, bytes32 _currencyKey, uint _burnAmount ) external; function fitToClaimable(address _from) external; function exit(address _from) external; function liquidateDelinquentAccount( address account, uint pusdAmount, address liquidator ) external returns (uint totalRedeemed, uint amountToLiquidate); } // Inheritance // Internal references // https://docs.peri.finance/contracts/source/contracts/addressresolver contract AddressResolver is Owned, IAddressResolver { mapping(bytes32 => address) public repository; constructor(address _owner) public Owned(_owner) {} /* ========== RESTRICTED FUNCTIONS ========== */ function importAddresses(bytes32[] calldata names, address[] calldata destinations) external onlyOwner { require(names.length == destinations.length, "Input lengths must match"); for (uint i = 0; i < names.length; i++) { bytes32 name = names[i]; address destination = destinations[i]; repository[name] = destination; emit AddressImported(name, destination); } } /* ========= PUBLIC FUNCTIONS ========== */ function rebuildCaches(MixinResolver[] calldata destinations) external { for (uint i = 0; i < destinations.length; i++) { destinations[i].rebuildCache(); } } /* ========== VIEWS ========== */ function areAddressesImported(bytes32[] calldata names, address[] calldata destinations) external view returns (bool) { for (uint i = 0; i < names.length; i++) { if (repository[names[i]] != destinations[i]) { return false; } } return true; } function getAddress(bytes32 name) external view returns (address) { return repository[name]; } function requireAndGetAddress(bytes32 name, string calldata reason) external view returns (address) { address _foundAddress = repository[name]; require(_foundAddress != address(0), reason); return _foundAddress; } function getPynth(bytes32 key) external view returns (address) { IIssuer issuer = IIssuer(repository["Issuer"]); require(address(issuer) != address(0), "Cannot find Issuer address"); return address(issuer.pynths(key)); } /* ========== EVENTS ========== */ event AddressImported(bytes32 name, address destination); } // solhint-disable payable-fallback // https://docs.peri.finance/contracts/source/contracts/readproxy contract ReadProxy is Owned { address public target; constructor(address _owner) public Owned(_owner) {} function setTarget(address _target) external onlyOwner { target = _target; emit TargetUpdated(target); } function() external { // The basics of a proxy read call // Note that msg.sender in the underlying will always be the address of this contract. assembly { calldatacopy(0, 0, calldatasize) // Use of staticcall - this will revert if the underlying function mutates state let result := staticcall(gas, sload(target_slot), 0, calldatasize, 0, 0) returndatacopy(0, 0, returndatasize) if iszero(result) { revert(0, returndatasize) } return(0, returndatasize) } } event TargetUpdated(address newTarget); } // Inheritance // Internal references // https://docs.peri.finance/contracts/source/contracts/mixinresolver contract MixinResolver { AddressResolver public resolver; mapping(bytes32 => address) private addressCache; constructor(address _resolver) internal { resolver = AddressResolver(_resolver); } /* ========== INTERNAL FUNCTIONS ========== */ function combineArrays(bytes32[] memory first, bytes32[] memory second) internal pure returns (bytes32[] memory combination) { combination = new bytes32[](first.length + second.length); for (uint i = 0; i < first.length; i++) { combination[i] = first[i]; } for (uint j = 0; j < second.length; j++) { combination[first.length + j] = second[j]; } } /* ========== PUBLIC FUNCTIONS ========== */ // Note: this function is public not external in order for it to be overridden and invoked via super in subclasses function resolverAddressesRequired() public view returns (bytes32[] memory addresses) {} function rebuildCache() public { bytes32[] memory requiredAddresses = resolverAddressesRequired(); // The resolver must call this function whenver it updates its state for (uint i = 0; i < requiredAddresses.length; i++) { bytes32 name = requiredAddresses[i]; // Note: can only be invoked once the resolver has all the targets needed added address destination = resolver.requireAndGetAddress(name, string(abi.encodePacked("Resolver missing target: ", name))); addressCache[name] = destination; emit CacheUpdated(name, destination); } } /* ========== VIEWS ========== */ function isResolverCached() external view returns (bool) { bytes32[] memory requiredAddresses = resolverAddressesRequired(); for (uint i = 0; i < requiredAddresses.length; i++) { bytes32 name = requiredAddresses[i]; // false if our cache is invalid or if the resolver doesn't have the required address if (resolver.getAddress(name) != addressCache[name] || addressCache[name] == address(0)) { return false; } } return true; } /* ========== INTERNAL FUNCTIONS ========== */ function requireAndGetAddress(bytes32 name) internal view returns (address) { address _foundAddress = addressCache[name]; require(_foundAddress != address(0), string(abi.encodePacked("Missing address: ", name))); return _foundAddress; } /* ========== EVENTS ========== */ event CacheUpdated(bytes32 name, address destination); } // https://docs.peri.finance/contracts/source/interfaces/iflexiblestorage interface IFlexibleStorage { // Views function getUIntValue(bytes32 contractName, bytes32 record) external view returns (uint); function getUIntValues(bytes32 contractName, bytes32[] calldata records) external view returns (uint[] memory); function getIntValue(bytes32 contractName, bytes32 record) external view returns (int); function getIntValues(bytes32 contractName, bytes32[] calldata records) external view returns (int[] memory); function getAddressValue(bytes32 contractName, bytes32 record) external view returns (address); function getAddressValues(bytes32 contractName, bytes32[] calldata records) external view returns (address[] memory); function getBoolValue(bytes32 contractName, bytes32 record) external view returns (bool); function getBoolValues(bytes32 contractName, bytes32[] calldata records) external view returns (bool[] memory); function getBytes32Value(bytes32 contractName, bytes32 record) external view returns (bytes32); function getBytes32Values(bytes32 contractName, bytes32[] calldata records) external view returns (bytes32[] memory); // Mutative functions function deleteUIntValue(bytes32 contractName, bytes32 record) external; function deleteIntValue(bytes32 contractName, bytes32 record) external; function deleteAddressValue(bytes32 contractName, bytes32 record) external; function deleteBoolValue(bytes32 contractName, bytes32 record) external; function deleteBytes32Value(bytes32 contractName, bytes32 record) external; function setUIntValue( bytes32 contractName, bytes32 record, uint value ) external; function setUIntValues( bytes32 contractName, bytes32[] calldata records, uint[] calldata values ) external; function setIntValue( bytes32 contractName, bytes32 record, int value ) external; function setIntValues( bytes32 contractName, bytes32[] calldata records, int[] calldata values ) external; function setAddressValue( bytes32 contractName, bytes32 record, address value ) external; function setAddressValues( bytes32 contractName, bytes32[] calldata records, address[] calldata values ) external; function setBoolValue( bytes32 contractName, bytes32 record, bool value ) external; function setBoolValues( bytes32 contractName, bytes32[] calldata records, bool[] calldata values ) external; function setBytes32Value( bytes32 contractName, bytes32 record, bytes32 value ) external; function setBytes32Values( bytes32 contractName, bytes32[] calldata records, bytes32[] calldata values ) external; } // Internal references // https://docs.peri.finance/contracts/source/contracts/mixinsystemsettings contract MixinSystemSettings is MixinResolver { bytes32 internal constant SETTING_CONTRACT_NAME = "SystemSettings"; bytes32 internal constant SETTING_WAITING_PERIOD_SECS = "waitingPeriodSecs"; bytes32 internal constant SETTING_PRICE_DEVIATION_THRESHOLD_FACTOR = "priceDeviationThresholdFactor"; bytes32 internal constant SETTING_ISSUANCE_RATIO = "issuanceRatio"; bytes32 internal constant SETTING_FEE_PERIOD_DURATION = "feePeriodDuration"; bytes32 internal constant SETTING_TARGET_THRESHOLD = "targetThreshold"; bytes32 internal constant SETTING_LIQUIDATION_DELAY = "liquidationDelay"; bytes32 internal constant SETTING_LIQUIDATION_RATIO = "liquidationRatio"; bytes32 internal constant SETTING_LIQUIDATION_PENALTY = "liquidationPenalty"; bytes32 internal constant SETTING_RATE_STALE_PERIOD = "rateStalePeriod"; bytes32 internal constant SETTING_EXCHANGE_FEE_RATE = "exchangeFeeRate"; bytes32 internal constant SETTING_MINIMUM_STAKE_TIME = "minimumStakeTime"; bytes32 internal constant SETTING_AGGREGATOR_WARNING_FLAGS = "aggregatorWarningFlags"; bytes32 internal constant SETTING_TRADING_REWARDS_ENABLED = "tradingRewardsEnabled"; bytes32 internal constant SETTING_DEBT_SNAPSHOT_STALE_TIME = "debtSnapshotStaleTime"; bytes32 internal constant SETTING_CROSS_DOMAIN_DEPOSIT_GAS_LIMIT = "crossDomainDepositGasLimit"; bytes32 internal constant SETTING_CROSS_DOMAIN_ESCROW_GAS_LIMIT = "crossDomainEscrowGasLimit"; bytes32 internal constant SETTING_CROSS_DOMAIN_REWARD_GAS_LIMIT = "crossDomainRewardGasLimit"; bytes32 internal constant SETTING_CROSS_DOMAIN_WITHDRAWAL_GAS_LIMIT = "crossDomainWithdrawalGasLimit"; bytes32 internal constant SETTING_EXTERNAL_TOKEN_QUOTA = "externalTokenQuota"; bytes32 internal constant SETTING_BRIDGE_TRANSFER_GAS_COST = "bridgeTransferGasCost"; bytes32 internal constant SETTING_BRIDGE_CLAIM_GAS_COST = "bridgeClaimGasCost"; bytes32 internal constant SETTING_SYNC_STALE_THRESHOLD = "syncStalThreshold"; bytes32 internal constant SETTING_EXTOKEN_ISSUANCE_RATIO = "exTokenIssuanceRatio"; bytes32 internal constant SETTING_LIQUIDATION_RATIOS = "liquidationRatios"; bytes32 internal constant CONTRACT_FLEXIBLESTORAGE = "FlexibleStorage"; enum CrossDomainMessageGasLimits {Deposit, Escrow, Reward, Withdrawal} constructor(address _resolver) internal MixinResolver(_resolver) {} function resolverAddressesRequired() public view returns (bytes32[] memory addresses) { addresses = new bytes32[](1); addresses[0] = CONTRACT_FLEXIBLESTORAGE; } function flexibleStorage() internal view returns (IFlexibleStorage) { return IFlexibleStorage(requireAndGetAddress(CONTRACT_FLEXIBLESTORAGE)); } function _getGasLimitSetting(CrossDomainMessageGasLimits gasLimitType) internal pure returns (bytes32) { if (gasLimitType == CrossDomainMessageGasLimits.Deposit) { return SETTING_CROSS_DOMAIN_DEPOSIT_GAS_LIMIT; } else if (gasLimitType == CrossDomainMessageGasLimits.Escrow) { return SETTING_CROSS_DOMAIN_ESCROW_GAS_LIMIT; } else if (gasLimitType == CrossDomainMessageGasLimits.Reward) { return SETTING_CROSS_DOMAIN_REWARD_GAS_LIMIT; } else if (gasLimitType == CrossDomainMessageGasLimits.Withdrawal) { return SETTING_CROSS_DOMAIN_WITHDRAWAL_GAS_LIMIT; } else { revert("Unknown gas limit type"); } } function getCrossDomainMessageGasLimit(CrossDomainMessageGasLimits gasLimitType) internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, _getGasLimitSetting(gasLimitType)); } function getTradingRewardsEnabled() internal view returns (bool) { return flexibleStorage().getBoolValue(SETTING_CONTRACT_NAME, SETTING_TRADING_REWARDS_ENABLED); } function getWaitingPeriodSecs() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_WAITING_PERIOD_SECS); } function getPriceDeviationThresholdFactor() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_PRICE_DEVIATION_THRESHOLD_FACTOR); } function getIssuanceRatio() internal view returns (uint) { // lookup on flexible storage directly for gas savings (rather than via SystemSettings) return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_ISSUANCE_RATIO); } function getFeePeriodDuration() internal view returns (uint) { // lookup on flexible storage directly for gas savings (rather than via SystemSettings) return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_FEE_PERIOD_DURATION); } function getTargetThreshold() internal view returns (uint) { // lookup on flexible storage directly for gas savings (rather than via SystemSettings) return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_TARGET_THRESHOLD); } function getLiquidationDelay() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_DELAY); } function getLiquidationRatio() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_RATIO); } function getLiquidationPenalty() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_LIQUIDATION_PENALTY); } function getRateStalePeriod() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_RATE_STALE_PERIOD); } function getExchangeFeeRate(bytes32 currencyKey) internal view returns (uint) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_EXCHANGE_FEE_RATE, currencyKey)) ); } function getMinimumStakeTime() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_MINIMUM_STAKE_TIME); } function getAggregatorWarningFlags() internal view returns (address) { return flexibleStorage().getAddressValue(SETTING_CONTRACT_NAME, SETTING_AGGREGATOR_WARNING_FLAGS); } function getDebtSnapshotStaleTime() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_DEBT_SNAPSHOT_STALE_TIME); } function getExternalTokenQuota() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_EXTERNAL_TOKEN_QUOTA); } function getBridgeTransferGasCost() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_BRIDGE_TRANSFER_GAS_COST); } function getBridgeClaimGasCost() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_BRIDGE_CLAIM_GAS_COST); } function getSyncStaleThreshold() internal view returns (uint) { return flexibleStorage().getUIntValue(SETTING_CONTRACT_NAME, SETTING_SYNC_STALE_THRESHOLD); } function getExTokenIssuanceRatio(bytes32 tokenKey) internal view returns (uint) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_EXTOKEN_ISSUANCE_RATIO, tokenKey)) ); } function getLiquidationRatios(bytes32 types) internal view returns (uint) { return flexibleStorage().getUIntValue( SETTING_CONTRACT_NAME, keccak256(abi.encodePacked(SETTING_LIQUIDATION_RATIOS, types)) ); } } // https://docs.peri.finance/contracts/source/contracts/limitedsetup contract LimitedSetup { uint public setupExpiryTime; /** * @dev LimitedSetup Constructor. * @param setupDuration The time the setup period will last for. */ constructor(uint setupDuration) internal { setupExpiryTime = now + setupDuration; } modifier onlyDuringSetup { require(now < setupExpiryTime, "Can only perform this action during setup"); _; } } /** * @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) { require(b <= a, "SafeMath: subtraction overflow"); 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-solidity/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) { // Solidity only automatically asserts when dividing by 0 require(b > 0, "SafeMath: division by zero"); 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) { require(b != 0, "SafeMath: modulo by zero"); return a % b; } } // Libraries // https://docs.peri.finance/contracts/source/libraries/safedecimalmath library SafeDecimalMath { using SafeMath for uint; /* Number of decimal places in the representations. */ uint8 public constant decimals = 18; uint8 public constant highPrecisionDecimals = 27; /* The number representing 1.0. */ uint public constant UNIT = 10**uint(decimals); /* The number representing 1.0 for higher fidelity numbers. */ uint public constant PRECISE_UNIT = 10**uint(highPrecisionDecimals); uint private constant UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR = 10**uint(highPrecisionDecimals - decimals); /** * @return Provides an interface to UNIT. */ function unit() external pure returns (uint) { return UNIT; } /** * @return Provides an interface to PRECISE_UNIT. */ function preciseUnit() external pure returns (uint) { return PRECISE_UNIT; } /** * @return The result of multiplying x and y, interpreting the operands as fixed-point * decimals. * * @dev A unit factor is divided out after the product of x and y is evaluated, * so that product must be less than 2**256. As this is an integer division, * the internal division always rounds down. This helps save on gas. Rounding * is more expensive on gas. */ function multiplyDecimal(uint x, uint y) internal pure returns (uint) { /* Divide by UNIT to remove the extra factor introduced by the product. */ return x.mul(y) / UNIT; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of the specified precision unit. * * @dev The operands should be in the form of a the specified unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function _multiplyDecimalRound( uint x, uint y, uint precisionUnit ) private pure returns (uint) { /* Divide by UNIT to remove the extra factor introduced by the product. */ uint quotientTimesTen = x.mul(y) / (precisionUnit / 10); if (quotientTimesTen % 10 >= 5) { quotientTimesTen += 10; } return quotientTimesTen / 10; } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a precise unit. * * @dev The operands should be in the precise unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, PRECISE_UNIT); } /** * @return The result of safely multiplying x and y, interpreting the operands * as fixed-point decimals of a standard unit. * * @dev The operands should be in the standard unit factor which will be * divided out after the product of x and y is evaluated, so that product must be * less than 2**256. * * Unlike multiplyDecimal, this function rounds the result to the nearest increment. * Rounding is useful when you need to retain fidelity for small decimal numbers * (eg. small fractions or percentages). */ function multiplyDecimalRound(uint x, uint y) internal pure returns (uint) { return _multiplyDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is a high * precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and UNIT must be less than 2**256. As * this is an integer division, the result is always rounded down. * This helps save on gas. Rounding is more expensive on gas. */ function divideDecimal(uint x, uint y) internal pure returns (uint) { /* Reintroduce the UNIT factor that will be divided out by y. */ return x.mul(UNIT).div(y); } /** * @return The result of safely dividing x and y. The return value is as a rounded * decimal in the precision unit specified in the parameter. * * @dev y is divided after the product of x and the specified precision unit * is evaluated, so the product of x and the specified precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ 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; } /** * @return The result of safely dividing x and y. The return value is as a rounded * standard precision decimal. * * @dev y is divided after the product of x and the standard precision unit * is evaluated, so the product of x and the standard precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRound(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, UNIT); } /** * @return The result of safely dividing x and y. The return value is as a rounded * high precision decimal. * * @dev y is divided after the product of x and the high precision unit * is evaluated, so the product of x and the high precision unit must * be less than 2**256. The result is rounded to the nearest increment. */ function divideDecimalRoundPrecise(uint x, uint y) internal pure returns (uint) { return _divideDecimalRound(x, y, PRECISE_UNIT); } /** * @dev Convert a standard decimal representation to a high precision one. */ function decimalToPreciseDecimal(uint i) internal pure returns (uint) { return i.mul(UNIT_TO_HIGH_PRECISION_CONVERSION_FACTOR); } /** * @dev Convert a high precision decimal to a standard decimal representation. */ 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 Round down the value with given number */ function roundDownDecimal(uint x, uint d) internal pure returns (uint) { return x.div(10**d).mul(10**d); } /** * @dev Round up the value with given number */ function roundUpDecimal(uint x, uint d) internal pure returns (uint) { uint _decimal = 10**d; if (x % _decimal > 0) { x = x.add(10**d); } return x.div(_decimal).mul(_decimal); } } // https://docs.peri.finance/contracts/source/interfaces/ierc20 interface IERC20 { // ERC20 Optional Views function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); // Views function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); // Mutative functions 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); // Events event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); } interface IStakingState { // Mutative function stake( bytes32 _currencyKey, address _account, uint _amount ) external; function unstake( bytes32 _currencyKey, address _account, uint _amount ) external; function refund( bytes32 _currencyKey, address _account, uint _amount ) external returns (bool); /* function setTargetRatio(address _account, uint _targetRatio) external; function setExTargetRatio(address _account, uint _exTRatio) external; */ // View function targetTokens(bytes32 _currencyKey) external view returns ( address tokenAddress, uint8 decimals, bool activated ); function stakedAmountOf(bytes32 _currencyKey, address _account) external view returns (uint); function totalStakedAmount(bytes32 _currencyKey) external view returns (uint); function totalStakerCount(bytes32 _currencyKey) external view returns (uint); function tokenList(uint _index) external view returns (bytes32); function tokenAddress(bytes32 _currencyKey) external view returns (address); function tokenDecimals(bytes32 _currencyKey) external view returns (uint8); function tokenActivated(bytes32 _currencyKey) external view returns (bool); function getTokenCurrencyKeys() external view returns (bytes32[] memory); /* function getTargetRatio(address _account) external view returns (uint); function getExTargetRatio(address _account) external view returns (uint); */ } // https://docs.peri.finance/contracts/source/interfaces/iexchangerates interface IExchangeRates { // Structs struct RateAndUpdatedTime { uint216 rate; uint40 time; } struct InversePricing { uint entryPoint; uint upperLimit; uint lowerLimit; bool frozenAtUpperLimit; bool frozenAtLowerLimit; } // Views function aggregators(bytes32 currencyKey) external view returns (address); function aggregatorWarningFlags() external view returns (address); function anyRateIsInvalid(bytes32[] calldata currencyKeys) external view returns (bool); function canFreezeRate(bytes32 currencyKey) external view returns (bool); function currentRoundForRate(bytes32 currencyKey) external view returns (uint); function currenciesUsingAggregator(address aggregator) external view returns (bytes32[] memory); function effectiveValue( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external view returns (uint value); function effectiveValueAndRates( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey ) external view returns ( uint value, uint sourceRate, uint destinationRate ); function effectiveValueAtRound( bytes32 sourceCurrencyKey, uint sourceAmount, bytes32 destinationCurrencyKey, uint roundIdForSrc, uint roundIdForDest ) external view returns (uint value); function getCurrentRoundId(bytes32 currencyKey) external view returns (uint); function getLastRoundIdBeforeElapsedSecs( bytes32 currencyKey, uint startingRoundId, uint startingTimestamp, uint timediff ) external view returns (uint); function inversePricing(bytes32 currencyKey) external view returns ( uint entryPoint, uint upperLimit, uint lowerLimit, bool frozenAtUpperLimit, bool frozenAtLowerLimit ); function lastRateUpdateTimes(bytes32 currencyKey) external view returns (uint256); function oracle() external view returns (address); function rateAndTimestampAtRound(bytes32 currencyKey, uint roundId) external view returns (uint rate, uint time); function rateAndUpdatedTime(bytes32 currencyKey) external view returns (uint rate, uint time); function rateAndInvalid(bytes32 currencyKey) external view returns (uint rate, bool isInvalid); function rateForCurrency(bytes32 currencyKey) external view returns (uint); function rateIsFlagged(bytes32 currencyKey) external view returns (bool); function rateIsFrozen(bytes32 currencyKey) external view returns (bool); function rateIsInvalid(bytes32 currencyKey) external view returns (bool); function rateIsStale(bytes32 currencyKey) external view returns (bool); function rateStalePeriod() external view returns (uint); function ratesAndUpdatedTimeForCurrencyLastNRounds(bytes32 currencyKey, uint numRounds) external view returns (uint[] memory rates, uint[] memory times); function ratesAndInvalidForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory rates, bool anyRateInvalid); function ratesForCurrencies(bytes32[] calldata currencyKeys) external view returns (uint[] memory); // Mutative functions function freezeRate(bytes32 currencyKey) external; } // https://docs.peri.finance/contracts/source/interfaces/iliquidations interface ILiquidations { // Views function isOpenForLiquidation(address account) external view returns (bool); function getLiquidationDeadlineForAccount(address account) external view returns (uint); function isLiquidationDeadlinePassed(address account) external view returns (bool); function liquidationDelay() external view returns (uint); function liquidationRatio(address account) external view returns (uint); function liquidationPenalty() external view returns (uint); // function calcAmtToFixCollateral(address account, uint debtBalance, uint collateral) external view returns (uint); // Mutative Functions function flagAccountForLiquidation(address account) external; // Restricted: used internally to Issuer function removeAccountInLiquidation(address account) external; function liquidateAccount( address account, address liquidator, uint pusdAmount, uint debtBalance ) external returns (uint totalRedeemed, uint amountToLiquidate); function checkAndRemoveAccountInLiquidation(address account) external; } contract ExternalTokenStakeManager is Owned, MixinResolver, MixinSystemSettings, LimitedSetup(8 weeks) { using SafeMath for uint; using SafeDecimalMath for uint; IStakingState public stakingState; bytes32 internal constant pUSD = "pUSD"; bytes32 internal constant PERI = "PERI"; bytes32 internal constant USDC = "USDC"; bytes32 public constant CONTRACT_NAME = "ExternalTokenStakeManager"; bytes32 private constant CONTRACT_ISSUER = "Issuer"; bytes32 private constant CONTRACT_EXRATES = "ExchangeRates"; bytes32 private constant CONTRACT_LIQUIDATIONS = "Liquidations"; // This key order is used from unstaking multiple coins // bytes32[] public currencyKeyOrder; constructor( address _owner, address _stakingState, address _resolver ) public Owned(_owner) MixinSystemSettings(_resolver) { stakingState = IStakingState(_stakingState); } function resolverAddressesRequired() public view returns (bytes32[] memory addresses) { bytes32[] memory existingAddresses = MixinSystemSettings.resolverAddressesRequired(); bytes32[] memory newAddresses = new bytes32[](3); newAddresses[0] = CONTRACT_ISSUER; newAddresses[1] = CONTRACT_EXRATES; newAddresses[2] = CONTRACT_LIQUIDATIONS; return combineArrays(existingAddresses, newAddresses); } function tokenInstance(bytes32 _currencyKey) internal view tokenRegistered(_currencyKey) returns (IERC20) { return IERC20(stakingState.tokenAddress(_currencyKey)); } function issuer() internal view returns (IIssuer) { return IIssuer(requireAndGetAddress(CONTRACT_ISSUER)); } function exchangeRates() internal view returns (IExchangeRates) { return IExchangeRates(requireAndGetAddress(CONTRACT_EXRATES)); } function liquidations() internal view returns (ILiquidations) { return ILiquidations(requireAndGetAddress(CONTRACT_LIQUIDATIONS)); } function getTokenList() external view returns (bytes32[] memory) { return stakingState.getTokenCurrencyKeys(); } function getTokenAddress(bytes32 _currencyKey) external view returns (address) { return stakingState.tokenAddress(_currencyKey); } function getTokenDecimals(bytes32 _currencyKey) external view returns (uint8) { return stakingState.tokenDecimals(_currencyKey); } function getTokenActivation(bytes32 _currencyKey) external view returns (bool) { return stakingState.tokenActivated(_currencyKey); } // function getCurrencyKeyOrder() external view returns (bytes32[] memory) { // return currencyKeyOrder; // } function combinedStakedAmountOf(address _user, bytes32 _unitCurrency) external view returns ( uint combinedSA /* , uint minDecimals */ ) { return _combinedStakedAmountOf(_user, _unitCurrency); } /* function compiledStakableAmountOf(address _user, bytes32 _unitCurrency) external view returns (uint) { return _compiledStakableAmountOf(_user, _unitCurrency); } */ function getExEADebt(address _account) external view returns ( uint exDebt, uint exEA, uint exTRatio ) { (exDebt, exEA, exTRatio) = _calcExEADebt(_account); } function getExDebt(address _account) external view returns (uint exDebt) { return _calcExDebt(_account); } function getTargetRatio(address _account, uint _existDebt) external view returns ( uint tRatio, uint exTRatio, uint exEA ) { (tRatio, exTRatio, exEA, , ) = _getTRatio(_account, _existDebt); } function getRatios( address _account, uint existDebt, uint periCol ) external view returns ( uint tRatio, uint cRatio, uint exTRatio, uint exEA, uint exSR, uint maxSR ) { return _tRatioCRatio(_account, existDebt, periCol); } function exStakingRatio(address _account, uint _existDebt) external view returns (uint exSR, uint maxSR) { (uint exDebt, uint exEA, uint exTRatio) = _calcExEADebt(_account); return _getExSR(_existDebt, exDebt, exEA, exTRatio); } function maxStakableAmountOf( address _account, uint _existDebt, uint _periCol, bytes32 _targetKey ) external view returns ( uint maxAmount /* , uint tRatio */ ) { // return _maxStakableAmountOf(_account, _existDebt, _targetKey, _unitKey); // (maxAmount, exTRatio, tRatio) = _maxExStakableAmt(_account, _existDebt, _periCol, _targetKey); (, , maxAmount) = _getTRAddDebtOrAmt(_account, _existDebt, 0, _periCol, _targetKey); // uint stakingAmt = _toCurrency(_unitKey, _targetKey, maxAmount); // uint targetDecimals = stakingState.tokenDecimals(_targetKey); // stakingAmt = stakingAmt.roundDownDecimal(uint(18).sub(targetDecimals)); // maxAmount = stakingAmt.div(10**(uint(18).sub(targetDecimals))); } /* function maxExAmtToTRatio( address _account, uint _existDebt, bytes32 _unitKey ) external view returns (uint) { return _maxExAmtToTRatio(_account, _existDebt, _unitKey); } */ function burnAmtToFitTR( address _account, uint _existDebt, uint _periCol ) external view returns ( uint burnAmount, uint exRefundAmt, uint exEA ) { return _burnAmtToFitTR(_account, _existDebt, _periCol); } /* function calcTRatio( address _account, uint _existDebt, uint _periCol, bytes32 _targetKey ) external view returns ( uint tRatio, uint exTRatio, uint eaSaGap ) { return _calcTRatio(_account, _existDebt, _periCol, _targetKey); } */ /* function calcTokenSR( uint exTR, uint tokenIR, uint otherIR ) external pure returns (uint) { return _tokenSR(exTR, tokenIR, otherIR); } */ /** * @notice calculate the pUSD value of the external tokens in user's wallet. * @dev external view function * @param _user user's wallet address * @param _currencyKey target currency key to be calculated */ function getTokenPUSDValueOf(address _user, bytes32 _currencyKey) external view returns (uint) { return _tokenPUSDValueOf(_user, _currencyKey); } /** * * @param _account user's wallet address * @param _amount the amount of debt to be removed * @param _unitKey the unit currency key for the amount */ function proRataUnstake( address _account, uint _amount, bytes32 _unitKey ) external returns (uint remainAmt) { // get ex-staked amount in unit currency (uint exDebt, uint exEA, uint exTRatio) = _calcExEADebt(_account); require(exDebt >= _amount, "Not enough external staked amount"); _amount = _preciseDivToDecimal(_amount, exTRatio); // remainAmt = _amount > exEA ? _amount.sub(exEA) : 0; // remainAmt = remainAmt.add(_proRataUnstake(_account, _account, _amount, exEA, _unitKey)); remainAmt = _proRataUnstake(_account, _account, _amount, exEA, _unitKey); } /* function proRataRefundAmt(address _account, uint _amount, bytes32 _unitKey) external view returns (uint overAmt, uint remainAmt) { (uint exDebt, uint exEA, uint exTRatio) = _calcExEADebt(_account); if(exDebt < _amount) return (_amount.sub(exDebt), 0); _amount = _preciseDivToDecimal(_amount, exTRatio); (_amount, overAmt) = _amount > exEA ? (exEA, _amount.sub(exEA)) : (_amount, 0); remainAmt = _proRataRefundAmt(_account, _amount, exEA, _unitKey); } */ /** * @notice calculate the pUSD value of the external tokens in user's wallet. * @dev internal view function * @param _user user's wallet address * @param _currencyKey target currency key to be calculated */ function _tokenPUSDValueOf(address _user, bytes32 _currencyKey) internal view returns (uint) { // (uint tokenRate, bool rateIsInvalid) = exchangeRates().rateAndInvalid(_currencyKey); // _requireRatesNotInvalid(rateIsInvalid); uint tokenRate = _rateCheck(_currencyKey); IERC20 exToken = tokenInstance(_currencyKey); uint balance = exToken.balanceOf(_user).mul(10**(uint(18).sub(exToken.decimals()))); return balance.multiplyDecimal(tokenRate); } /* /** * @notice calculate the max pUSD value of the external tokens in user's wallet. * * @param _user user's wallet address * @param _currencyKey target currency key to be calculated */ /* function maxSAPulsTokensOf(address _user, bytes32 _currencyKey) external view returns (uint maxStakableAmt) { require(_currencyKey != pUSD && _currencyKey != PERI, "PERI and pUSD not allowed"); maxStakableAmt = _combinedStakedAmountOf(_user, pUSD); return maxStakableAmt.add(_tokenPUSDValueOf(_user, _currencyKey)); } */ /* function expectedTargetRatios( address _account, uint _existDebt, uint _amount, bytes32 _targetKey, bool _stake ) external view returns ( uint exTargetRatio, uint targetRatio, uint changedAmt ) { (exTargetRatio, targetRatio, changedAmt) = _expectedTargetRatios(_account, _existDebt, _amount, _targetKey, _stake); } */ function stakedAmountOf( address _user, bytes32 _currencyKey, bytes32 _unitCurrency ) external view returns (uint) { return _stakedAmountOf(_user, _currencyKey, _unitCurrency); } function _stakedAmountOf( address _user, bytes32 _currencyKey, bytes32 _unitCurrency ) internal view returns (uint amountOf) { amountOf = stakingState.stakedAmountOf(_currencyKey, _user); if (amountOf == 0) { return 0; } if (_currencyKey == _unitCurrency) { return amountOf; } amountOf = _toCurrency(_currencyKey, _unitCurrency, amountOf); // amountOf = amountOf.roundDownDecimal(uint(18).sub(stakingState.tokenDecimals(_currencyKey))); } // function requireNotExceedsQuotaLimit( // address _account, // uint _debtBalance, // uint _additionalpUSD, // uint _additionalExToken, // bool _isIssue // ) external view { // uint estimatedExternalTokenQuota = // externalTokenQuota(_account, _debtBalance, _additionalpUSD, _isIssue); // bytes32[] memory tokenList = stakingState.getTokenCurrencyKeys(); // uint minDecimals = 18; // for (uint i; i < tokenList.length; i++) { // uint decimals = stakingState.tokenDecimals(tokenList[i]); // minDecimals = decimals < minDecimals ? decimals : minDecimals; // } // require( // // due to the error caused by decimal difference, round down it upto minimum decimals among staking token list. // estimatedExternalTokenQuota.roundDownDecimal(uint(18).sub(minDecimals)) <= getExternalTokenQuota(), // "External token staking amount exceeds quota limit" // ); // } // /** // * @notice It calculates the quota of user's staked amount to the debt. // * If parameters are not 0, it estimates the quota assuming those value is applied to current status. // * // * @param _account account // * @param _debtBalance Debt balance to estimate [USD] // * @param _addAmt amount to ex-staked amount [USD] // * @param _isIssue If true, it is staking. Otherwise, it is unstaking. // */ /* function externalTokenQuota( address _account, uint _debtBalance, uint _addAmt, bool _isIssue ) external view returns (uint exTargetRatio) { // (exTargetRatio, , ) = _expectedTargetRatios(_account, _debtBalance, _addAmt, USDC, _isIssue); } */ function _getExSR( uint _existDebt, /* uint _periCol, */ uint _exDebt, uint _exEA, uint _exTRatio ) internal view returns (uint exSR, uint maxSR) { if (_exEA == 0) return (0, 0); uint periIR = getIssuanceRatio(); uint periSA = _existDebt > _exDebt ? _existDebt.sub(_exDebt) : 0; periSA = _preciseDivToDecimal(periSA, periIR); // totalSA = periSA + _exEA // periSA = periSA > _periCol ? _periCol.add(_exEA) : periSA.add(_exEA); periSA = periSA.add(_exEA); exSR = _exEA.divideDecimal(periSA); // Se = (T - Tp) / (Te - Tp) maxSR = _preciseDivToDecimal(getExternalTokenQuota().sub(periIR), _exTRatio.sub(periIR)); } function _tRatioCRatio( address _account, uint _existDebt, uint _periCol ) internal view returns ( uint tRatio, uint cRatio, uint exTRatio, uint exEA, uint exSR, uint maxSR ) { (tRatio, exTRatio, exEA, exSR, maxSR) = _getTRatio(_account, _existDebt); uint totalSA = _periCol.add(exEA); cRatio = totalSA > 0 ? _existDebt.divideDecimal(totalSA) : 0; } function _getTRatio(address _account, uint _existDebt) internal view returns ( uint tRatio, uint exTRatio, uint exEA, uint exSR, uint maxSR ) { if (_existDebt == 0) { return (getIssuanceRatio(), SafeDecimalMath.unit(), 0, 0, 0); } // get tokenEA, otherEA, tokenIR, otherIR // uint tokenIR; uint otherIR; // uint otherEA; // uint tokenEA; // uint exDebt; // (otherIR, otherEA, tokenIR, tokenEA, exDebt) = _otherTokenIREA(_account, USDC); // // get exEA // exEA = tokenEA.add(otherEA); uint exDebt; (exDebt, exEA, exTRatio) = _calcExEADebt(_account); uint periIR = getIssuanceRatio(); // uint maxTR = getExternalTokenQuota(); if (exEA == 0) { return (periIR, SafeDecimalMath.unit(), 0, 0, 0); } // // get peri SA = periDebt / peri issuance ratio // otherEA = _existDebt > exDebt ? _preciseDivToDecimal(_existDebt.sub(exDebt), periIR) : 0; // // get exTRatio (Te = To - (To - Tt) * St) // exTRatio = _toTRatio(otherIR, tokenIR, tokenEA.divideDecimal(exEA)); // // Se-max = (Tmax - Tp) / (Te - Tp) // otherIR = _preciseDivToDecimal(maxTR.sub(periIR), exTRatio.sub(periIR)); // // get external Target Staking Ratio and save it to otherIR // uint exSR = exEA.divideDecimal(exEA.add(otherEA)); // exSR = exSR > otherIR ? otherIR : exSR; (exSR, maxSR) = _getExSR(_existDebt, exDebt, exEA, exTRatio); exDebt = exSR > maxSR ? maxSR : exSR; // get TRatio (Tp + ( Te - Tp) * Se) tRatio = _toTRatio(periIR, exTRatio, exDebt); // tRatio = tRatio > maxTR ? maxTR : tRatio < periIR ? periIR : tRatio; } // function _targetRatio(address _account) internal view returns (uint tRatio) { // tRatio = stakingState.getTargetRatio(_account); // tRatio = tRatio == 0 ? getIssuanceRatio() : tRatio; // } function _rateCheck(bytes32 _currencyKey) internal view returns (uint rate) { bool isInvalid; (rate, isInvalid) = exchangeRates().rateAndInvalid(_currencyKey); _requireRatesNotInvalid(isInvalid); } function _preciseMul(uint x, uint y) internal pure returns (uint) { return (y == 0 || x == 0) ? 0 : x.decimalToPreciseDecimal().multiplyDecimalRoundPrecise(y.decimalToPreciseDecimal()); } function _preciseDiv(uint x, uint y) internal pure returns (uint) { return (y == 0 || x == 0) ? 0 : x.decimalToPreciseDecimal().divideDecimalRoundPrecise(y.decimalToPreciseDecimal()); } function _preciseMulToDecimal(uint x, uint y) internal pure returns (uint) { return (y == 0 || x == 0) ? 0 : _preciseMul(x, y).preciseDecimalToDecimal(); } function _preciseDivToDecimal(uint x, uint y) internal pure returns (uint) { return (y == 0 || x == 0) ? 0 : _preciseDiv(x, y).preciseDecimalToDecimal(); } /** * @notice calculate the total staked value of the external tokens of the staker in given currency unit. * * @param _user staker address * @param _unitCurrency The currency unit to be applied for estimation [USD] */ function _combinedStakedAmountOf(address _user, bytes32 _unitCurrency) internal view returns ( uint combinedStakedAmount /* , uint minDecimals */ ) { bytes32[] memory tokenList = stakingState.getTokenCurrencyKeys(); // minDecimals = 18; for (uint i; i < tokenList.length; i++) { uint stakedAmount = _stakedAmountOf(_user, tokenList[i], _unitCurrency); if (stakedAmount == 0) { continue; } combinedStakedAmount = combinedStakedAmount.add(stakedAmount); // uint decimals = stakingState.tokenDecimals(tokenList[i]); // minDecimals = decimals < minDecimals ? decimals : minDecimals; } } /* /** * @notice calculate stakable amount of the external tokens in the staker's wallet. * * @return stakable amount of the external tokens in the staker's wallet. * @param _user staker address * @param _unitCurrency The currency unit to be applied for estimation [USD] */ /* function _compiledStakableAmountOf(address _user, bytes32 _unitCurrency) internal view returns (uint compiledStakableAmount) { bytes32[] memory tokenList = stakingState.getTokenCurrencyKeys(); for (uint i; i < tokenList.length; i++) { uint _stakedAmount = stakingState.stakedAmountOf(tokenList[i], _user); if (_stakedAmount == 0) { continue; } _stakedAmount = tokenInstance(tokenList[i]).balanceOf(_user).mul(10**(18 - (uint)(tokenInstance(tokenList[i]).decimals()))) - _stakedAmount; compiledStakableAmount = compiledStakableAmount.add(_toCurrency(tokenList[i], _unitCurrency, _stakedAmount)); } } */ /** * @notice calculate the value in given currency unit. * * @return convAmt the value in given currency unit. * @param _fromKey The currency key of the external token * @param _toKey The currency key to be converted * @param _amount The amount of the external token */ function _toCurrency( bytes32 _fromKey, bytes32 _toKey, uint _amount ) internal view returns (uint convAmt) { if (_fromKey == _toKey) { return _amount; } convAmt = _amount; // uint amountToUSD; uint rate; // bool rateIsInvalid; if (_fromKey != pUSD) { // if (_fromKey == pUSD) { // amountToUSD = _amount; // } else { // (rate, rateIsInvalid) = exchangeRates().rateAndInvalid(_fromKey); // _requireRatesNotInvalid(rateIsInvalid); rate = _rateCheck(_fromKey); // amountToUSD = _amount.multiplyDecimalRound(rate); // convAmt = _amount.multiplyDecimalRound(rate); convAmt = _preciseMulToDecimal(_amount, rate); } if (_toKey != pUSD) { // if (_toKey == pUSD) { // return amountToUSD; // } else { // (rate, rateIsInvalid) = exchangeRates().rateAndInvalid(_toKey); // _requireRatesNotInvalid(rateIsInvalid); rate = _rateCheck(_toKey); // return convAmt.divideDecimalRound(rate); // convAmt = convAmt.divideDecimalRound(rate); convAmt = _preciseDivToDecimal(convAmt, rate); } } /** * @notice Utils checking given two key arrays' value are matching each other(its order will not be considered). */ function _keyChecker(bytes32[] memory _keysA, bytes32[] memory _keysB) internal pure returns (bool) { if (_keysA.length != _keysB.length) { return false; } for (uint i; i < _keysA.length; i++) { bool exist; for (uint j; j < _keysA.length; j++) { if (_keysA[i] == _keysB[j]) { exist = true; break; } } // given currency key is not matched if (!exist) { return false; } } return true; } function _calcExDebt(address _account) internal view returns (uint exDebt) { // get exEA (, , , , exDebt) = _otherTokenIREA(_account, USDC); // get exDebt = tokenEA * tokenIR + otherEA * otherIR // exDebt = _preciseMulToDecimal(tokenEA, tokenIR).add( // _preciseMulToDecimal(otherEA, otherIR) // ); } // function _calcTotalSA(address _account, uint _existDebt) // internal view returns (uint totalSA, uint exEA, uint exDebt) { // (exDebt, exEA,) = _calcExDebt(_account); // // get peri debt amount // totalSA = _preciseDivToDecimal(_existDebt.sub(exDebt), getIssuanceRatio()); // } function _calcExEADebt(address _account) internal view returns ( uint exDebt, uint exEA, uint exTRatio /* , uint minDecimals */ ) { // get exEA uint otherIR; uint otherEA; uint tokenIR; uint tokenEA; (otherIR, otherEA, tokenIR, tokenEA, exDebt) = _otherTokenIREA(_account, USDC); // // get exDebt = tokenEA * tokenIR + otherEA * otherIR // exDebt = _preciseMulToDecimal(tokenEA, tokenIR).add( // _preciseMulToDecimal(otherEA, otherIR) // ); // get exEA exEA = tokenEA.add(otherEA); // get exTRatio exTRatio = exEA > 0 ? _toTRatio(otherIR, tokenIR, tokenEA.divideDecimal(exEA)) : SafeDecimalMath.unit(); } /* /** * @notice calculate unstake amount of the external tokens with the given amount and debt * * @param _account staker address * @param _amount the amount of debt to be removed * @param _existDebt existing debt amount * @param _periCol PERI collateral amount * @param _targetKey external token key * * @return exRefundAmt unstaking ex-token amount in pUSD */ /* function _calcUnstakeAmt( address _account, uint _amount, uint _existDebt, uint _periCol, bytes32 _targetKey ) internal view returns (uint exRefundAmt) { exRefundAmt = _calcExDebt(_account); // calc peri debt amount uint periDebt = _existDebt > exRefundAmt ? _existDebt.sub(exRefundAmt) : 0; // get peri estimated debt from the collateral value uint periCol2Debt = _preciseMulToDecimal(_periCol, getIssuanceRatio()); // calc the gap between periDebt and periCol2Debt and check if it is short or long exRefundAmt = periDebt > periCol2Debt ? periDebt.sub(periCol2Debt) : 0; // in case short, check if the amount is more than the gap. if amount > gap, unstake amount = amount - gap else amount itself // in case long, unstake amount is amount + gap exRefundAmt = exRefundAmt > 0 ? _amount > exRefundAmt ? _preciseMulToDecimal(_amount.sub(exRefundAmt), getExTokenIssuanceRatio(_targetKey)) : 0 : _preciseMulToDecimal(_amount, getExTokenIssuanceRatio(_targetKey)); } */ /** * @notice get the other token's Issuance Ratio and Staked Amount * (if the target token is stable, this is gold token such as PAXG or vice versa) * * @param _account staker address * @param _targetKey external token key * * @return otherIR other token's Issuance Ratio * @return otherEA other token's Staked Amount * @return tokenIR target token's Issuance Ratio */ function _otherTokenIREA(address _account, bytes32 _targetKey) internal view returns ( uint otherIR, uint otherEA, uint tokenIR, uint tokenEA, uint exDebt /* , uint minDecimals */ ) { tokenIR = getExTokenIssuanceRatio(_targetKey); uint minDecimals = 18; uint oMinDecimals = 18; bytes32[] memory tokenList = stakingState.getTokenCurrencyKeys(); for (uint i; i < tokenList.length; i++) { exDebt = _stakedAmountOf(_account, tokenList[i], pUSD); if (tokenIR != getExTokenIssuanceRatio(tokenList[i])) { otherIR = getExTokenIssuanceRatio(tokenList[i]); if (exDebt > 0) { otherEA = otherEA.add(exDebt); exDebt = stakingState.tokenDecimals(tokenList[i]); oMinDecimals = oMinDecimals < exDebt ? oMinDecimals : exDebt; } } else if (exDebt > 0) { tokenEA = tokenEA.add(exDebt); exDebt = stakingState.tokenDecimals(tokenList[i]); minDecimals = minDecimals < exDebt ? minDecimals : exDebt; } } exDebt = _preciseMulToDecimal(tokenEA, tokenIR).roundDownDecimal(uint(18).sub(minDecimals)).add( _preciseMulToDecimal(otherEA, otherIR).roundDownDecimal(uint(18).sub(oMinDecimals)) ); // minDecimals = minDecimals < oMinDecimals ? minDecimals : oMinDecimals; } function otherTokenIREA(address _account, bytes32 _targetKey) external view returns ( uint otherIR, uint otherEA, uint tokenIR, uint tokenEA /* , uint minDecimals */ ) { (otherIR, otherEA, tokenIR, tokenEA, ) = _otherTokenIREA(_account, _targetKey); } function tokenStakeStatus(address _account) external view returns ( bytes32[] memory tokenList, uint[] memory stakedAmts, uint[] memory decimals, uint[] memory balances ) { tokenList = stakingState.getTokenCurrencyKeys(); stakedAmts = new uint[](tokenList.length); decimals = new uint[](tokenList.length); balances = new uint[](tokenList.length); /* tokenIRs = new uint[](tokenList.length); */ for (uint i; i < tokenList.length; i++) { stakedAmts[i] = stakingState.stakedAmountOf(tokenList[i], _account); decimals[i] = stakingState.tokenDecimals(tokenList[i]); balances[i] = tokenInstance(tokenList[i]).balanceOf(_account); // balances[i] = decimals[i] < uint(18) // ? balances[i].mul(10**(uint(18).sub(decimals[i]))) // : balances[i]; } } /* /** * @notice get total external tokens' staking ratio * * @param _account staker address * @param targetRatio external tokens' target ratio */ /* function _exStakingRatio(address _account, uint targetRatio) internal view returns (uint exSR) { // if target ratio is 0, return exSR 0 // if (targetRatio == getIssuanceRatio()) { // return 0; // } // get external tokens' target ratio exSR = stakingState.getExTargetRatio(_account); // get total external tokens' target ratio // Ex-Staking Ratio = (Target Ratio - Peri Issuance Ratio) / (Sum of Ex-Token Target Ratio - Peri Issuance Ratio) exSR = _preciseDivToDecimal(targetRatio.sub(getIssuanceRatio()), exSR.sub(getIssuanceRatio())); } */ /* /** * @notice get target token's staking ratio * @dev St = (To-Te) / (To-Tt) * @param exTR external token's target ratio * @param tokenIR target token's issuance ratio * @param otherIR the other token's issuance ratio */ /* function _tokenSR( uint exTR, uint tokenIR, uint otherIR ) internal pure returns (uint tokenSR) { // get target token's staking ratio // Token Staking Ratio = +/-( Ex-Target Ratio - Token Issuance Ratio ) / +/-( Token Issuance Ratio - Other Issuance Ratio ) tokenSR = tokenIR > otherIR ? _preciseDivToDecimal(exTR.sub(otherIR), tokenIR.sub(otherIR)) : _preciseDivToDecimal(otherIR.sub(exTR), otherIR.sub(tokenIR)); } */ /* /** * @notice get target token's staking ratio and the other token's issuance ratio(if the target token is stable, this is Gold token such as PAXG) * @dev only keeps 2 types of external tokens' staking ratio. one is * , the other is non-stables such as PAXG. * @param _account staker address * @param _targetKey external token key * * @return tokenER target token's staking ratio * @return otherIR the other token's issuance ratio * @return tokenIR target token's issuance ratio */ /* function _tokenER(address _account, bytes32 _targetKey) internal view returns ( uint tokenER, uint otherIR, uint tokenIR ) { // get the other token's issuance ratio if the target token is stable, it is non-stable token such as PAXG // tokenER(Estimated Value Ratio) = otherEA(other type's Estimated Value Amount) at the moment uint tokenEA; (otherIR, tokenER, tokenIR, tokenEA, ) = _otherTokenIREA(_account, _targetKey); // if there is no other token, return tokenER 0, otherIR, tokenIR if (tokenEA == 0) { return (0, otherIR, tokenIR); } // get target token's estimated value ratio tokenER = tokenEA / ( tokenEA + otherEA ) tokenER = _preciseDivToDecimal(tokenEA, tokenEA.add(tokenER)); } */ /* /** * @notice get max ex-tokens' stakable amount in _unitKey for the current target ratio * * @param _account staker address * @param _existDebt existing debt amount * @param _unitKey external token key * * @return maxAmount max ex-tokens' stakable amount in _unitKey for the current target ratio */ /* function _maxExAmtToTRatio( address _account, uint _existDebt, bytes32 _unitKey ) internal view returns (uint maxAmount) { uint tRatio = _targetRatio(_account); // get max stakable amount : maxAmt = Debt Balance * Staking Ratio / Target Ratio maxAmount = _preciseMulToDecimal(_existDebt, _exStakingRatio(_account, tRatio)); maxAmount = _preciseDivToDecimal(maxAmount, tRatio); // convert maxAmount to _unitKey if (_unitKey != pUSD) { maxAmount = _preciseDivToDecimal(maxAmount, _rateCheck(_unitKey)); } } */ /** * @notice get burn amount to meet the current target ratio * * @param _account staker address * @param _existDebt existing debt amount * @param _periCol PERI collateral amount * * @return burnAmount burn amount * @return exRefundAmt ex-refund amount */ function _burnAmtToFitTR( address _account, uint _existDebt, uint _periCol ) internal view returns ( uint burnAmount, uint exRefundAmt, uint exEA ) { // get ex-debt and ex-staked amount uint exDebt; uint exTRatio; (exDebt, exEA, exTRatio) = _calcExEADebt(_account); // require(exEA > 0, "No external token staked"); if (exEA == 0) { exDebt = _preciseMulToDecimal(_periCol, getIssuanceRatio()); burnAmount = _existDebt > exDebt ? _existDebt.sub(exDebt) : 0; return (burnAmount, 0, 0); } /* // get total SA(D) uint tmpEA = _existDebt > exDebt ? _preciseDivToDecimal(_existDebt.sub(exDebt), getIssuanceRatio()).add(exEA) : exEA; //_preciseDivToDecimal(_existDebt, exTRatio); // calc max ex-token value upto max target ratio(0.5) // maxAmt = { (Tmax - Tp) * V + (Te - Tp) * Ve } / (Te - Tmax) tmpEA = _preciseMulToDecimal(tmpEA, getExternalTokenQuota().sub(getIssuanceRatio())); uint tmpExEA = _preciseMulToDecimal(tmpEA, exTRatio.sub(getIssuanceRatio())); exRefundAmt = tmpExEA > tmpEA ? _preciseDivToDecimal(tmpExEA.sub( exEA ), exTRatio.sub(getExternalTokenQuota())) : 0; exDebt = exRefundAmt > 0 ? _preciseMulToDecimal(exEA.sub(exRefundAmt), exTRatio) : exDebt; // get peri estimated debt from the collateral value uint periCol2Debt = _preciseMulToDecimal(_periCol, getIssuanceRatio()); // get periDebt uint periDebt = _existDebt.sub(exDebt); burnAmount = periDebt > periCol2Debt ? periDebt.sub(periCol2Debt) : 0; */ uint periIR = getIssuanceRatio(); uint maxSR = getExternalTokenQuota(); // get ex-staking ratio for max target ratio(0.5) // Se-max = (Tmax - Tp) / (Te - Tp) uint tmpExSR = _preciseDivToDecimal(maxSR.sub(periIR), exTRatio.sub(periIR)); // get exSA for max target ratio(0.5) and save it to tmpExEA uint tmpExEA = _preciseDivToDecimal(_existDebt, maxSR); tmpExEA = _preciseMulToDecimal(tmpExEA, tmpExSR); // get peri estimated debt from the collateral value uint periCol2Debt = _preciseMulToDecimal(_periCol, periIR); // in case exDebt > maxExDebt, periDebt = existDebt - maxExDebt, // otherwiase periDebt = existDebt - exDebt uint periDebt = exEA > tmpExEA ? _existDebt.sub(_preciseMulToDecimal(tmpExEA, exTRatio)) : _existDebt.sub(exDebt); // when periDebt is bigger than peri collateral-converted debt if (periDebt > periCol2Debt) { // fix max EX-token Staking Amount with peri's collateral and max exSR (exSA = periCol * exSR / (1 - exSR) tmpExEA = _preciseDivToDecimal(_preciseMulToDecimal(_periCol, tmpExSR), SafeDecimalMath.unit().sub(tmpExSR)); // calc max debt amount by adding periCol2Debt and max exDebt exDebt = periCol2Debt.add(exEA > tmpExEA ? _preciseMulToDecimal(tmpExEA, exTRatio) : exDebt); // calc burn amount by substracting sum of max exDebt and periCol2Debt from existDebt burnAmount = _existDebt > exDebt ? _existDebt.sub(exDebt) : 0; // // calc exRefundAmt by substracting max ex-tokens' SA from ex-tokens' SA // exRefundAmt = tmpExEA >= exEA ? exEA.sub(tmpExEA) : 0; } // calc exRefundAmt by substracting max ex-tokens' SA from ex-tokens' SA exRefundAmt = exEA > tmpExEA ? exEA.sub(tmpExEA) : 0; /* uint periDebt; // if exDebt is bigger than max exDebt if (exEA > tmpExEA) { // convert the exSA to exDebt for max target ratio(0.5) and get periDebt periDebt = _existDebt.sub(tmpExEA.multiplyDecimal(exTRatio)); // when periDebt is bigger than peri collateral-converted debt if (periDebt > periCol2Debt) { // calc max EX-token Staking Amount with peri's collateral and max exSR tmpExEA = _periCol.multiplyDecimal(tmpExSR).divideDecimal(SafeDecimalMath.unit().sub(tmpExSR)); // calc burn amount by substracting sum of max exDebt and periCol2Debt from existDebt burnAmount = _existDebt.sub(periCol2Debt.add(tmpExEA.multiplyDecimal(exTRatio))); } // calc exRefundAmt by substracting max ex-tokens' SA from ex-tokens' SA exRefundAmt = exEA.sub(tmpExEA); // when exDebt is smaller than max exDebt } else { // get periDebt periDebt = _existDebt.sub(exDebt); // burnAmount = (periDebt > periCol2Debt) ? periDebt.sub(periCol2Debt) : 0; if (periDebt > periCol2Debt) { // calc max EX-token Staking Amount with peri's collateral and max exSR tmpExEA = _periCol.multiplyDecimal(tmpExSR).divideDecimal(SafeDecimalMath.unit().sub(tmpExSR)); // calc burn amount by substracting sum of max exDebt and periCol2Debt from existDebt burnAmount = _existDebt.sub(periCol2Debt.add(tmpExEA.multiplyDecimal(exTRatio))); // calc exRefundAmt by substracting max ex-tokens' SA from ex-tokens' SA exRefundAmt = exEA.sub(tmpExEA); } } */ } /* /** * @notice get needed ex-tokens amount in _unitKey to meet max target ratio (ex. 0.5) * @dev needed amount(to max target ratio) * X = { ( Tt - Tp ) * Vt + ( To - Tp ) * Do - ( Tmax - Tp ) * (D - Dt + Vt) } / ( Tmax - Tt ) * @param _account staker address * @param _existDebt existing debt amount * @param _unitKey external token key * * @return exTRatio ex-tokens' staking ratio * @return addableAmt needed ex-tokens amount in _unitKey to meet max target ratio (ex. 0.5) */ /* function _maxStakableAmountOf( address _account, uint _existDebt, bytes32 _targetKey, bytes32 _unitKey ) internal view returns (uint exTRatio, uint addableAmt) { // get tokenEA(Vt), tokenIR(Tt), otherEA, otherIR(To) and decimals (uint otherIR, uint otherEA, uint tokenIR, uint tokenEA, ) = _otherTokenIREA(_account, _targetKey); exTRatio = _targetRatio(_account); // get total SA(D) : totalSA = _existDebt / Target Ratio uint debt2ToSA = _existDebt.divideDecimal(exTRatio); // get ex-staking ratio(exSR) and ex-staked amount(exSA) uint exSA = debt2ToSA.multiplyDecimal(_exStakingRatio(_account, exTRatio)); // if exSA < exEA return (0, 0) if (exSA < tokenEA.add(otherEA)) { return (0, 0); } // calc otherSA(Do) : otherSA = exSA * otherSR otherEA = exSA != 0 ? _preciseMulToDecimal(_tokenSR(stakingState.getExTargetRatio(_account), otherIR, tokenIR), exSA) : 0; // get target token's stakable amount getExternalTokenQuota() = Tmax // X = [ ( Tmax - Tp ) * (D + Vt - Dt) - { ( Tt - Tp ) * Vt + ( To - Tp ) * Do } ] / ( Tt - Tmax ) // addableAmt = ( Tt - Tp ) * Vt : always Tt > Tp addableAmt = _preciseMulToDecimal(tokenIR.sub(getIssuanceRatio()), tokenEA); // addableAmt = addableAmt + ( To - Tp ) * Do : always To > Tp addableAmt = addableAmt.add(_preciseMulToDecimal(otherIR.sub(getIssuanceRatio()), otherEA)); // calc tokenSA(Dt) : tokenSA = tokenSR * exSA exSA = exSA != 0 ? _preciseMulToDecimal(_tokenSR(stakingState.getExTargetRatio(_account), tokenIR, otherIR), exSA) : 0; // debt2ToSA = ( Tmax - Tp ) * (D + Vt - Dt) debt2ToSA = _preciseMulToDecimal(getExternalTokenQuota().sub(getIssuanceRatio()), debt2ToSA.add(tokenEA).sub(exSA)); // if target token's EA > target token's SA, return (token's SA, 0) if (debt2ToSA < addableAmt) { return (exSA, 0); } // addableAmt = ( Tmax - Tp ) * (D + Vt - Dt) - addableAmt : always Tmax > Tp addableAmt = debt2ToSA.sub(addableAmt); // addableAmt = addableAmt / ( Tt - Tmax ) addableAmt = _preciseDivToDecimal(addableAmt, tokenIR.sub(getExternalTokenQuota())); // round down it upto minimum decimals among staking token list. addableAmt = addableAmt.roundDownDecimal(uint(18).sub(stakingState.tokenDecimals(_targetKey))); // we need to consider the decimals of the ex-token. // get all of _currencyKey token's amount of from the user wallet uint tokenPUSDValue = _tokenPUSDValueOf(_account, _targetKey); // cap the staking amount within the user's wallet amount addableAmt = tokenPUSDValue < addableAmt ? tokenPUSDValue : addableAmt; if (_unitKey != pUSD) { // addableAmt = _preciseDivToDecimal(addableAmt, _rateCheck(_unitKey)); addableAmt = addableAmt.divideDecimal(_rateCheck(_unitKey)); } // get token's staking ratio and save it to exTRatio exTRatio = tokenEA.add(addableAmt).divideDecimal(tokenEA.add(addableAmt).add(otherEA)); // get exTRatio exTRatio = _toTRatio(otherIR, tokenIR, exTRatio); } */ /* /** * @notice get new target ratio of the staker * @dev _debt2TotSA should not be exeeded the staked tokens' total amount in USD, which means _debt2TotSA needs to be caluculated before calling this function. * _debt2TotSA can be calculated by combinedStakedAmountOf() function or stakedAmountOf() function with token key. * @param _amount external token amount in USD * @param _debt2TotSA existing total staked amount based on the existing debt * @param _debt2ExSA external token's staking amount based on the existing debt * @param _periIR Peri Issuance Ratio * @param _exTargetRatio external token's target ratio * @param _stake if true, it is staking, otherwise unstaking */ /* function _calcTargetRatio( uint _amount, uint _debt2TotSA, uint _debt2ExSA, uint _periIR, uint _exTargetRatio, bool _stake ) internal pure returns (uint estTargetRatio) { // if _ex-Staking Amount is 0, it means there is no external token staked yet, so _stake must be true if (!_stake && _debt2ExSA == 0) { return 0; } // get new staking ratio(var: estTargetRatio) : // Ex-Staking Ratio = (Staked Amount(Ex) +/- Ex-Staking Amount) / ( Staked Amount(Total) +/- Ex-Staking Amount) estTargetRatio = !_stake ? _debt2ExSA > _amount ? _debt2ExSA.sub(_amount).divideDecimal(_debt2TotSA.sub(_amount)) : 0 // : _preciseDivToDecimal(_debt2ExSA.add(_amount), _debt2TotSA.add(_amount)); : _debt2ExSA.add(_amount).divideDecimal(_debt2TotSA.add(_amount)); // get new target ratio(var: estTargetRatio) : // Target Ratio = Peri Issuance Ratio - (Peri Issuance Ratio - Ex-Target Ratio) * Ex-Staking Ratio estTargetRatio = _toTRatio(_periIR, _exTargetRatio, estTargetRatio); // estTargetRatio = targetRatio.decimalToPreciseDecimal().multiplyDecimalRoundPrecise(SafeDecimalMath.unit().sub(estTargetRatio)) // .add(exTargetRatio.decimalToPreciseDecimal().multiplyDecimalRoundPrecise(estTargetRatio)).preciseDecimalToDecimal(); } */ /* /** * @notice calculate new target ratios of the staker * * @param _account staker address * @param _existDebt existing debt amount * @param _amount adding/subtracting token value amount * @param _targetKey external token key * @param _stake if true, it is staking, otherwise unstaking * * @return exTargetRatio external token's target ratio * @return targetRatio total external tokens' target ratio * @return changedAmt if staking, CHANGED DEBT amount, if not, UNSTAKING amount in USD */ /* function _expectedTargetRatios( address _account, uint _existDebt, uint _amount, bytes32 _targetKey, bool _stake ) internal view returns ( uint exTargetRatio, uint targetRatio, uint changedAmt ) { // get the staker's Target Ratio targetRatio = _targetRatio(_account); // get the staker's existing staked amount in USD based on existing debt (debt / target ratio) uint debt2totSA = _preciseDivToDecimal(_existDebt, targetRatio); // get the staker's old external staked amount in USD based on the debt and the external staking ratio uint debt2ExSA = _preciseMulToDecimal(debt2totSA, _exStakingRatio(_account, targetRatio)); // get the staker's External token Target Ratio (exTargetRatio, changedAmt) = _expectedExTargetRatio(_account, debt2ExSA, _amount, _targetKey, _stake); // get the staker's Target Ratio targetRatio = _calcTargetRatio(changedAmt, debt2totSA, debt2ExSA, getIssuanceRatio(), exTargetRatio, _stake); } */ /* /** * @notice calculate new ex-target ratio of the staker * * @param _account staker address * @param _debt2ExSA existing debt amount * @param _amount external token amount * @param _targetKey external token key * @param _stake if true, it is staking, otherwise unstaking * * @return exTRatio external token's target ratio * @return changedAmt if staking, CHANGED DEBT amount, if not, UNSTAKING amount in USD */ /* function _expectedExTargetRatio( address _account, uint _debt2ExSA, uint _amount, bytes32 _targetKey, bool _stake ) internal view returns (uint exTRatio, uint changedAmt) { // get ex-target ratio exTRatio = stakingState.getExTargetRatio(_account); if (exTRatio == SafeDecimalMath.unit()) { return (getExTokenIssuanceRatio(_targetKey), _amount); } // get the other token's Issuance Ratio, target token's Issuance Ratio and target token's Staked Amount (uint otherIR, , uint tokenIR, uint tokenEA, ) = _otherTokenIREA(_account, _targetKey); // get target SR : St = (To-Te) / (To-Tt) uint tokenSR = _tokenSR(exTRatio, tokenIR, otherIR); // get target token's staked amount in USD based on the debt uint tokenSA = tokenSR != 0 ? _preciseMulToDecimal(_debt2ExSA, tokenSR) : 0; // applying the decimals of the target token. tokenSA = tokenSA.roundDownDecimal(uint(18).sub(stakingState.tokenDecimals(_targetKey))); // get SA change in order for debt change in USD changedAmt = tokenEA.add(_amount); _amount = _stake ? changedAmt > tokenSA ? changedAmt.sub(tokenSA) : 0 : tokenEA > tokenSA ? _amount > tokenEA.sub(tokenSA) ? _amount.sub(tokenEA.sub(tokenSA)) : _amount : _amount; // if _amount is 0, return exTRatio, 0 if (_amount == 0) { return (exTRatio, 0); } // calc staking/ unstaking amount in USD changedAmt = _stake ? _amount : tokenSA >= tokenEA ? _amount >= tokenSA.sub(tokenEA) ? _amount.sub(tokenSA.sub(tokenEA)) : 0 : _amount.add(tokenEA.sub(tokenSA)); // calc new target token's Staking Ratio tokenSR = _stake ? tokenSA.add(_amount).divideDecimal(_debt2ExSA.add(_amount)) : tokenSA > _amount ? tokenSA.sub(_amount).divideDecimal(_debt2ExSA.sub(_amount)) : 0; // get new ex-target ratio(var: exTRatio) : // Ex-Target Ratio = other Issuance Ratio - (other Issuance Ratio - token Issuance Ratio) * token Staking Ratio exTRatio = _toTRatio(otherIR, tokenIR, tokenSR); } */ function _toTRatio( uint _Tp, uint _Te, uint _Se ) internal pure returns (uint) { // Target Ratio = Peri Issuance Ratio - (Peri Issuance Ratio - Ex-Staking Ratio) * Ex-Staking Ratio (uint temp, bool sub) = _Tp > _Te ? (_Tp.sub(_Te), true) : (_Te.sub(_Tp), false); return sub ? _Tp.sub(_preciseMulToDecimal(temp, _Se)) : _Tp.add(_preciseMulToDecimal(temp, _Se)); } /* function calcInitTargetRatios( address _account, uint _periCol ) external view onlyIssuer returns ( uint exTRatio, uint tRatio, uint maxIDebt ) { return _calcInitTargetRatios( _account, _periCol ); } */ /* /** * @notice calulate re-initializable the staker's Target Ratios * * @param _account staker address * @param _periCol Peri Collateral amount */ /* function _calcInitTargetRatios( address _account, uint _periCol ) internal view returns ( uint tRatio, uint exTRatio, uint maxIDebt ) { // get the other token's issuance ratio that is non-stable token such as PAXG (uint otherIR, uint otherEA, uint tokenIR, uint tokenEA, ) = _otherTokenIREA(_account, USDC); // if no exEA, return tRatio 0.25 if (otherEA == 0 && tokenEA == 0) { return (getIssuanceRatio(), SafeDecimalMath.unit(), _preciseMulToDecimal(getIssuanceRatio(), _periCol)); } // get old target ratio tRatio = _targetRatio(_account); // get old total SA(D) : totalSA = _existDebt / Target Ratio // uint debt2totSA = _preciseDivToDecimal(_existDebt, tRatio); // calc ex-tokens's Estimated Value(exEA) tokenEA = otherEA.add(tokenEA); // calc the other token's staking ratio(ex: PAXG) uint otherSR = tokenEA > 0 ? _preciseDivToDecimal(otherEA, tokenEA) : 0; // Ex-Target Ratio = Stable Issuance Ratio - (Stable Issuance Ratio - Other(ex PAXG) Issuance Ratio) * Other(ex:PAXG) Staking Ratio exTRatio = otherSR > 0 ? _toTRatio(tokenIR, otherIR, otherSR) : SafeDecimalMath.unit(); // sum ex-tokens' estimated value and peri collateral to get max stakable value { peri(all in the wallet) + ex-tokens(staked) } maxIDebt = _periCol.add(tokenEA); // calc new ex-token's staking ratio otherSR = tokenEA.divideDecimal(maxIDebt); // calc new target ratio // Target Ratio = Peri Issuance Ratio - (Peri Issuance Ratio - Ex-Target Ratio) * Ex-Staking Ratio tRatio = _toTRatio(getIssuanceRatio(), exTRatio, otherSR); _requireOverIssuanceRatio(tRatio); // get max issuable debt : max issuable debt = (max issuable value - staked value) * tRatio maxIDebt = _preciseMulToDecimal(tRatio, maxIDebt); } */ /* /** * @notice get needed ex-tokens amount in _unitKey to meet max target ratio (ex. 0.5) * @dev needed amount(to max target ratio) * X = { ( Tt - Tp ) * Vt + ( To - Tp ) * Vo - ( Tmax - Tp ) * V } / ( Tmax - Tt ) * @param _account staker address * @param _existDebt existing debt amount * @param _periCol PERI collateral amount * @param _targetKey external token key * * @return exTRatio ex-tokens' staking ratio * @return addableAmt needed ex-tokens amount in _unitKey to meet max target ratio (ex. 0.5) */ /* function _maxExStakableAmt( address _account, uint _existDebt, uint _periCol, bytes32 _targetKey ) internal view returns ( uint addableAmt, uint exTRatio, uint tRatio ) { // get tokenEA(Vt), tokenIR(Tt), otherEA(Vo), otherIR(To) and decimals (uint otherIR, uint otherEA, uint tokenIR, uint tokenEA, ) = _otherTokenIREA(_account, _targetKey); tRatio = _targetRatio(_account); // get total SA(D) : totalSA = _existDebt / Target Ratio uint totalSA = _existDebt.divideDecimal(tRatio); // get taltal EA(V) : totalSA = totalSA + exEA - exSA totalSA = totalSA.add(tokenEA.add(otherEA)).sub(totalSA.multiplyDecimal(_exStakingRatio(_account, tRatio))); // get target token's stakable amount getExternalTokenQuota() = Tmax // X = [ ( Tmax - Tp ) * V - { ( Tt - Tp ) * Vt + ( To - Tp ) * Vo } ] / ( Tt - Tmax ) // addableAmt = ( Tt - Tp ) * Vt : always Tt > Tp addableAmt = _preciseMulToDecimal(tokenIR.sub(getIssuanceRatio()), tokenEA); // addableAmt = addableAmt + ( To - Tp ) * Vo : always To > Tp addableAmt = addableAmt.add(_preciseMulToDecimal(otherIR.sub(getIssuanceRatio()), otherEA)); // tempAmt = ( Tmax - Tp ) * V uint tempAmt = _preciseMulToDecimal(getExternalTokenQuota().sub(getIssuanceRatio()), totalSA); // if target token's EA > target token's SA, return (old exTRatio, 0) if (tempAmt < addableAmt) { return (0, stakingState.getExTargetRatio(_account), tRatio); } // addableAmt = ( Tmax - Tp ) * V - addableAmt : always Tmax > Tp addableAmt = tempAmt.sub(addableAmt); // addableAmt = addableAmt / ( Tt - Tmax ) addableAmt = _preciseDivToDecimal(addableAmt, tokenIR.sub(getExternalTokenQuota())); // round down it upto minimum decimals among staking token list. addableAmt = addableAmt.roundDownDecimal(uint(18).sub(stakingState.tokenDecimals(_targetKey))); // we need to consider the decimals of the ex-token. // get all of _currencyKey token's amount of from the user wallet uint tokenPUSDValue = _tokenPUSDValueOf(_account, _targetKey); // cap the staking amount within the user's wallet amount addableAmt = tokenPUSDValue < addableAmt ? tokenPUSDValue : addableAmt; // calc new exSA and save it to tempAmt: exSA = exEA + addableAmt tempAmt = tokenEA.add(addableAmt).add(otherEA); // get max SA uint maxSA = _periCol.add(tempAmt); // get total SA totalSA = totalSA.add(addableAmt); // adjust the changed amount and totalSA if totalSA is over maxSA (addableAmt, totalSA) = totalSA > maxSA ? (addableAmt > totalSA.sub(maxSA) ? addableAmt.sub(totalSA.sub(maxSA)) : 0, maxSA) : (addableAmt, totalSA); // get token's staking ratio and save it to exTRatio exTRatio = tokenEA.add(addableAmt).divideDecimal(tempAmt); // get new exTRatio exTRatio = _toTRatio(otherIR, tokenIR, exTRatio); // calc new exSR and save it to tRatio tRatio = tempAmt.divideDecimal(totalSA); // calc new tRatio : tRatio = Tp + ( Te - Tp) * Se tRatio = _toTRatio(getIssuanceRatio(), exTRatio, tRatio); } */ function _calcMaxStakableAmt( uint _tokenIR, uint _otherIR, uint _tokenEA, uint _otherEA, uint _totalEA ) internal view returns (uint addableAmt) { uint periIR = getIssuanceRatio(); uint maxSR = getExternalTokenQuota(); // get target token's stakable amount getExternalTokenQuota() = Tmax // X = [ ( Tmax - Tp ) * V - { ( Tt - Tp ) * Vt + ( To - Tp ) * Vo } ] / ( Tt - Tmax ) // addableAmt = ( Tt - Tp ) * Vt : always Tt > Tp uint temp = _tokenIR.sub(periIR); addableAmt = _preciseMulToDecimal(temp, _tokenEA); // addableAmt = addableAmt + ( To - Tp ) * Vo : always To > Tp temp = _preciseMulToDecimal(_otherIR > 0 ? _otherIR.sub(periIR) : 0, _otherEA); addableAmt = addableAmt.add(temp); // temp = ( Tmax - Tp ) * V : always Tmax > Tp temp = maxSR.sub(periIR); temp = _preciseMulToDecimal(temp, _totalEA); // if target token's EA > target token's SA, return (old exTRatio, 0) if (temp < addableAmt) { return 0; } // addableAmt = ( Tmax - Tp ) * V - addableAmt addableAmt = temp.sub(addableAmt); // addableAmt = addableAmt / ( Tt - Tmax ) temp = _tokenIR.sub(maxSR); addableAmt = _preciseDivToDecimal(addableAmt, temp); } /** * @notice get target token's staking ratio if _addAmt is 0, it retruns current target ratio. if not it returns new target ratio with _addAmt * ( periCol * Tp + stableEA * Ts + paxg * To ) < _existDebt --> lower c-Ratio : burning debt is first thing to do. * both ex-token staking and peri staking need to remove debt first and if there is any extra staking amount, it can be converted to newly added debt. * X = [ ( Tmax - Tp ) * V - { ( Tt - Tp ) * Vt + ( To - Tp ) * Vo } ] / ( Tt - Tmax ) * if ex-token staking amount reaches to max, no more ex-token staking is allowed. * if periSA > periCol, any ex-token staking can't compensate peri's over-collateral debt. ex-token staking is only possible to compensate its max addable amount of debt. * @param _account staker address * @param _existDebt existing debt amount * @param _addAmt adding token value amount * @param _targetKey external token key * * @return tRatio target ratio * @return addableAmt max stakable amount in USD(exMaxStakableAmt call) * @return addDebt adding debt amount in USD */ function _getTRAddDebtOrAmt( address _account, uint _existDebt, uint _addAmt, uint _periCol, bytes32 _targetKey ) internal view returns ( uint tRatio, uint addDebt, uint addableAmt ) { if (_existDebt == 0) { return (getIssuanceRatio(), 0, 0); } // get tokenEA, otherEA, tokenIR, otherIR, exDebt (uint otherIR, uint otherEA, uint tokenIR, uint tokenEA, uint exDebt) = _otherTokenIREA(_account, _targetKey == bytes32(0) ? USDC : _targetKey); // get exEA uint exEA = tokenEA.add(otherEA); // // get exDebt = tokenEA * tokenIR + otherEA * otherIR // uint exDebt = _preciseMulToDecimal(tokenEA, tokenIR).add( // _preciseMulToDecimal(otherEA, otherIR) // ); // get peri debt amount uint periDebt = _existDebt > exDebt ? _existDebt.sub(exDebt) : 0; // if _addAmt is not 0, the function call while staking ex-token. // if _targetKey is not 0, the function call is for getting max ex-stakable amount. if (_addAmt != 0 || _targetKey != bytes32(0)) { // if max ex-stakable amount call if (_addAmt == 0) { // calc total SA = exEA + (periDebt / PERI Issuance Ratio) addDebt = exEA.add( periDebt > _preciseMulToDecimal(_periCol, getIssuanceRatio()) ? _periCol : _preciseDivToDecimal(periDebt, getIssuanceRatio()) ); // get addable amount within max ex-issuance ratio addableAmt = _calcMaxStakableAmt(tokenIR, otherIR, tokenEA, otherEA, addDebt); // get all of _currencyKey token's amount of from the user wallet addDebt = _tokenPUSDValueOf(_account, _targetKey); // cap the staking amount within the user's wallet amount addableAmt = addDebt < addableAmt ? addDebt : addableAmt; addDebt = _preciseMulToDecimal(addableAmt, getExTokenIssuanceRatio(_targetKey)); // if staking ex-token call } else { // get adding debt(addDebt) and staking amount(_addAmt) in USD (addDebt, addableAmt) = (_addAmt, _preciseDivToDecimal(_addAmt, getExTokenIssuanceRatio(_targetKey))); addableAmt = addableAmt.roundDownDecimal(uint(18).sub(stakingState.tokenDecimals(_targetKey))); } // ** check if ex-token staking is able to compensate over-collateral debt // if exist periDebt is less than periCol2Debt, which means there is enough PERI in the wallet, set adding debt = addDebt // if not and addDebt is more than periDebt - periCol2Debt, // which means PERI value in the wallen doss not cover addDebt + existing debt but covers existing debt, // set adding debt = addDebt - (periDebt - periCol2Debt) // otherwise, adding debt = 0 // get peri-collateral-converted debt : periCol2Debt = periCol * Tp _periCol = _preciseMulToDecimal(_periCol, getIssuanceRatio()); addDebt = periDebt > _periCol ? addDebt > periDebt.sub(_periCol) ? addDebt.sub(periDebt.sub(_periCol)) : 0 : addDebt; // ** get updated exEA and ex-debt // update tokenEA = tokenEA + addableAmt tokenEA = tokenEA.add(addableAmt); // update exEA = updated tokenEA + otherEA exEA = tokenEA.add(otherEA); // update periDebt = tokenEA * tokenIR + otherEA * otherIR exDebt = _preciseMulToDecimal(tokenEA, tokenIR).add(_preciseMulToDecimal(otherEA, otherIR)); // update periDebt = _existDebt + addDebt - exDebt _existDebt = _existDebt.add(addDebt); periDebt = _existDebt > exDebt ? _existDebt.sub(exDebt) : 0; } // if no exEA, return getIssuanceRatio(), 0, _preciseDivToDecimal(_existDebt, getIssuanceRatio()) if (exEA == 0) { return (getIssuanceRatio(), addDebt, addableAmt); } // get peri SA = periDebt / peri issuance ratio periDebt = _preciseDivToDecimal(periDebt, getIssuanceRatio()); // get exTRatio and save it to tRatio (Te = To - (To - Tt) * St) tRatio = _toTRatio(otherIR, tokenIR, tokenEA.divideDecimal(exEA)); // get ex-Staking Ratio and calc TRatio (Tp + ( Te - Tp) * Se) tRatio = _toTRatio(getIssuanceRatio(), tRatio, exEA.divideDecimal(exEA.add(periDebt))); } /* /** * @notice calulate changed external token's staking amount, new target ratios and ex-target ratio * * @param _account staker address * @param _existDebt existing debt amount * @param _periCol Peri Collateral amount * @param _targetKey external token key * * @return tRatio target ratio * @return exTRatio external token's target ratio * @return changedAmt External Changed Staked Aamount(exCSA) in USD */ /* function _calcTRatio( address _account, uint _existDebt, uint _periCol, bytes32 _targetKey ) internal view returns ( uint tRatio, uint exTRatio, uint exChangeSA ) { // get the staker's Target Ratio tRatio = _targetRatio(_account); // get the staker's existing staked amount in USD based on existing debt (debt / target ratio) uint totalSA = _preciseDivToDecimal(_existDebt, tRatio); // get the staker's old external staked amount in USD based on the debt and the external staking ratio uint exSA = _preciseMulToDecimal(totalSA, _exStakingRatio(_account, tRatio)); // get the other token's Issuance Ratio, target token's Issuance Ratio and target token's Staked Amount (uint otherIR, uint otherEA, uint tokenIR, uint tokenEA, ) = _otherTokenIREA(_account, _targetKey); // get ex-target ratio exTRatio = stakingState.getExTargetRatio(_account); // get target SR : St = (To-Te) / (To-Tt) uint tokenSA = _tokenSR(exTRatio, tokenIR, otherIR); // get target token's staked amount in USD based on the debt tokenSA = _preciseMulToDecimal(exSA, tokenSA); // applying the decimals of the ex-token. tokenSA = tokenSA > 0 ? tokenSA.roundDownDecimal(uint(18).sub(stakingState.tokenDecimals(_targetKey))) : 0; // calc external staked amount(exEA) and save it to otherEA uint exEA = tokenEA.add(otherEA); // if there is no newly added debt, return exTRatio if (tokenEA <= tokenSA) { return (tRatio, exTRatio, 0); } // get Max SA and save it to tokenSA uint maxSA = _periCol.add(exEA); // get changed amount exChangeSA = tokenEA.sub(tokenSA); totalSA = totalSA.add(exEA).sub(exSA); // (exTRatio, tRatio, exChangeSA) = _calcSAChange(exChangeSA, totalSA, maxSA, tokenEA, exEA, tokenIR, otherIR); (exChangeSA, totalSA) = totalSA > maxSA ? (exChangeSA > totalSA.sub(maxSA) ? exChangeSA.sub(totalSA.sub(maxSA)) : 0, maxSA) : (exChangeSA, totalSA); // get token's staking ratio and save it to exTRatio exTRatio = tokenEA.divideDecimal(exEA); // get new exTRatio exTRatio = _toTRatio(otherIR, tokenIR, exTRatio); // calc new exSR and save it to tRatio tRatio = exEA.divideDecimal(totalSA); // calc new tRatio : tRatio = Tp + ( Te - Tp) * Se tRatio = _toTRatio(getIssuanceRatio(), exTRatio, tRatio); } */ /* ========== MUTATIVE FUNCTIONS ========== */ /* function setTargetRatios( address _account, uint _tRatio, uint _exTRatio ) external onlyIssuer { stakingState.setExTargetRatio(_account, _exTRatio); stakingState.setTargetRatio(_account, _tRatio); } */ /* function _saveTRatios( address _account, uint _existDebt, uint _periCol, bytes32 _targetKey ) internal returns (uint changedAmt) { // get the staker's expected External token Target Ratio and Target Ratio uint tRatio; uint exTRatio; (tRatio, exTRatio, changedAmt) = _calcTRatio(_account, _existDebt, _periCol, _targetKey); // only if it is staking, check the new target ratio is over the max external issuance ratio // _requireOverIssuanceRatio(tRatio); // set the staker's External token Target Ratio stakingState.setExTargetRatio(_account, exTRatio); // set the staker's Target Ratio stakingState.setTargetRatio(_account, tRatio); } */ /* /** * @notice It sets 2 target ratios of the staker. * * @param _account staker address * @param _existDebt existing debt amount * @param _amount newly adding debt amount * @param _targetKey the external key to be staked * @param _stake if true, it is staking, otherwise unstaking */ /* function _setTargetRatios( address _account, uint _existDebt, uint _amount, bytes32 _targetKey, bool _stake ) internal returns (uint changedAmt) { // get the staker's expected External token Target Ratio and Target Ratio uint exTRatio; uint tRatio; (exTRatio, tRatio, changedAmt) = _expectedTargetRatios(_account, _existDebt, _amount, _targetKey, _stake); // only if it is staking, check the new target ratio is over the max issuance ratio require(!_stake || tRatio <= getExternalTokenQuota(), "over max issuance ratio"); // set the staker's External token Target Ratio stakingState.setExTargetRatio(_account, exTRatio); // set the staker's Target Ratio stakingState.setTargetRatio(_account, tRatio); } */ function stakeToMaxExQuota( address _account, uint _existDebt, uint _periCol, bytes32 _targetKey ) external onlyIssuer returns (uint debtChange) { // this function is not to inculde the other token's staked value decrease. // (uint exTRatio, uint maxAddableAmt) = _maxStakableAmountOf(_account, _existDebt, _targetKey, _unitKey); // this fuction is to include the other token's staked value decrease in order to get the max stakable value. // (uint maxAddableAmt, uint exTRatio, uint tRatio) = _maxExStakableAmt(_account, _existDebt, _periCol, _targetKey); uint maxAddableAmt; uint tRatio; (tRatio, debtChange, maxAddableAmt) = _getTRAddDebtOrAmt(_account, _existDebt, 0, _periCol, _targetKey); require(maxAddableAmt > 0, "No available ex-tokens to stake"); // check if the new target ratio is out of allowed external issuance ratio _requireOverIssuanceRatio(tRatio); // stake the external token _stakeTokens(_account, maxAddableAmt, _targetKey, pUSD); // debtChange : issuing debt amount // debtChange = _preciseMulToDecimal(getExTokenIssuanceRatio(_targetKey), maxAddableAmt); // set ex-target ratio // stakingState.setExTargetRatio(_account, exTRatio); // set target ratio // stakingState.setTargetRatio(_account, tRatio); } function stake( address _account, uint _amount, uint _existDebt, uint _periCol, bytes32 _targetKey, bytes32 _unitKey ) external onlyIssuer returns (uint debtChange) { uint tRatio; (tRatio, debtChange, _amount) = _getTRAddDebtOrAmt(_account, _existDebt, _amount, _periCol, _targetKey); _requireOverIssuanceRatio(tRatio); // applying target ratio ( debt to SA ) = (debt / target ratio) // changing _amount from requested issuing debt to requested staking amount // _amount = _preciseDivToDecimal(_amount, getExTokenIssuanceRatio(_targetKey)); // set the staker's External token Target Ratio and Target Ratio // _amount : requested staking amount // debtChange = _setTargetRatios(_account, _existDebt, _amount, _targetKey, true); _stakeTokens(_account, _amount, _targetKey, _unitKey); // save the staker's Target Ratios // debtChange = _saveTRatios(_account, _existDebt, _periCol, _targetKey); // debtChange : issuing debt amount // debtChange = _preciseMulToDecimal(getExTokenIssuanceRatio(_targetKey), debtChange); } /** * @notice It stakes the external token to the staking contract * * @param _staker staker address * @param _amount adding staking value amount in unit currency * @param _targetKey the external key to be staked * @param _unitKey the unit currency key */ function _stakeTokens( address _staker, uint _amount, bytes32 _targetKey, bytes32 _unitKey ) internal { // get the staking amount in target currency uint stakingAmt = _toCurrency(_unitKey, _targetKey, _amount); uint decimals = stakingState.tokenDecimals(_targetKey); require(decimals <= 18, "Invalid decimal number"); decimals = uint(18).sub(decimals); stakingAmt = stakingAmt.roundDownDecimal(decimals); // uint balance = exToken.balanceOf(_staker).mul(10**(decimals)); require( tokenInstance(_targetKey).transferFrom(_staker, address(stakingState), stakingAmt.div(10**decimals)), "Transferring staking token has been failed" ); stakingState.stake(_targetKey, _staker, stakingAmt); } /** * @notice unstakes and moves the external token to the staker's wallet. * * @param _staker the staker address * @param _amount unit currency amount * @param _targetKey the external key to be unstaked * @param _unitKey the unit currency key */ function unstake( address _staker, uint _amount, /* uint _curDebt, uint _periCol, */ bytes32 _targetKey, bytes32 _unitKey ) external onlyIssuer { // changing _amount from requested issuing debt to requested staking amount _amount = _preciseDivToDecimal(_amount, getExTokenIssuanceRatio(_targetKey)); // _amount = _calcUnstakeAmt(_staker, _amount, _curDebt, _periCol, _targetKey); // set the staker's External token Target Ratio and Target Ratio // _setTargetRatios(_staker, _existDebt, _amount, _targetKey, false); // convert the un-staking amount to one in target currency // and unstake the external token _unstakeAndRefund(_staker, _staker, _toCurrency(_unitKey, _targetKey, _amount), _targetKey); } // /** // * // * @param _staker target staker address getting liquidated // * @param _liquidator taker address // * @param _amount unit currency amount getting liquidated // * @param _targetKey the external key to be unstaked // * @param _unitKey the unit currency key // */ // function unstakeAndLiquidate( // address _staker, // address _liquidator, // uint _amount, // bytes32 _targetKey, // bytes32 _unitKey // ) external onlyIssuer { // uint outUnitAmount = _toCurrency(_unitKey, _targetKey, _amount); // _unstakeAndRefund(_staker, _liquidator, outUnitAmount, _targetKey); // } /** * @notice It redeems the external token to move off the debt. * * @param _account the account address to redeem * @param _amount total amount to move off the debt * * @param _liquidator the liquidator address */ function redeem( address _account, uint _amount, address _liquidator ) external onlyLiquidations returns (uint remainAmt) { // get ex-staked amount in unit currency uint exEA = _combinedStakedAmountOf(_account, pUSD); (_amount, remainAmt) = _amount > exEA ? (exEA, _amount.sub(exEA)) : (_amount, 0); exEA = _proRataUnstake(_account, _liquidator, _amount, exEA, pUSD); remainAmt = remainAmt.add(exEA); // _initTargetRatios(_account, _existDebt.sub(_amount)); /* remainAmount = amount; bytes32[] memory tokenList = stakingState.getTokenCurrencyKeys(); for (uint i; i < tokenList.length; i++) { if (tokenList[i] == PERI) { continue; } if (remainAmount == 0) { break; } // staked token amount uint stakedAmt = _stakedAmountOf(account, tokenList[i], tokenList[i]); // if there is staked amount left if (stakedAmt > 0) { // convert th token amount to pUSD amount uint usdAmount = _toCurrency(tokenList[i], pUSD, stakedAmt); // staked pUSD value is bgger than remainAmount(getting liquidated pUSD value) if (remainAmount < usdAmount) { // replace usdAmount to remainAmount usdAmount = remainAmount; // convert the pUSD amount to the token amount stakedAmt = _toCurrency(pUSD, tokenList[i], usdAmount); } //uint unstakingAmountConverted = _toCurrency(tokenList[i], pUSD, redeemed); //_unstakeAndRefund(account, liquidator, unstakingAmountConverted, tokenList[i]); // unstake staked tokens and reward the liquidator _unstakeAndRefund(account, liquidator, stakedAmt, tokenList[i]); // subtract to-be-moved-off-debt amount by already moved off debt amount remainAmount = remainAmount.sub(usdAmount); } } */ } /* function _proRataRefundAmt(address _staker, uint _amount, uint exEA, bytes32 _unitKey) internal view returns(uint remainAmount) { // uint totUnstake = _amount > exEA ? exEA : _amount; uint stakedAmt; uint unstakAmt; uint decimals; uint tokenSR; // set the currency key order if currencyKeyOrder is not set bytes32[] memory keys = stakingState.getTokenCurrencyKeys(); for (uint i; i < keys.length; i++) { // get the staked amount of the token stakedAmt = _stakedAmountOf(_staker, keys[i], _unitKey); // if the amount to be unstaked is 0, move to the next token if (stakedAmt == 0) { continue; } // get the token's staking ratio against ex-staked amount tokenSR = stakedAmt.divideDecimal(exEA); // get unstake amount unstakAmt = _preciseMulToDecimal(_amount, tokenSR).add(remainAmount); // get remain amount and cap unstakAmt within stakedAmt (remainAmount, unstakAmt) = unstakAmt > stakedAmt ? (unstakAmt.sub(stakedAmt), stakedAmt) : (0, unstakAmt); // convert the unstake amount to the token amount unstakAmt = _toCurrency(_unitKey, keys[i], unstakAmt); // get the token's decimals decimals = stakingState.tokenDecimals(keys[i]); if (uint(18) > decimals) { tokenSR = unstakAmt; unstakAmt = unstakAmt.roundDownDecimal(uint(18).sub(decimals)); // update remainAmount tokenSR = tokenSR.sub(unstakAmt); tokenSR = _toCurrency(keys[i], _unitKey, tokenSR); remainAmount = remainAmount.add(tokenSR); } } } */ /** * @notice It unstakes multiple tokens by pre-defined order. * @dev internal function * @param _staker staker address * @param _taker taker address * @param _amount amount to get unstaked in unit currency * @param _unitKey the currency unit of _amount * */ function _proRataUnstake( address _staker, address _taker, uint _amount, uint exEA, bytes32 _unitKey ) internal returns (uint remainAmount) { // uint totUnstake = _amount > exEA ? exEA : _amount; uint stakedAmt; uint unstakAmt; uint decimals; uint tokenSR; uint minDecimals = 16; // set the currency key order if currencyKeyOrder is not set bytes32[] memory keys = stakingState.getTokenCurrencyKeys(); for (uint i; i < keys.length; i++) { // get the staked amount of the token stakedAmt = _stakedAmountOf(_staker, keys[i], _unitKey); // if the amount to be unstaked is 0, move to the next token if (stakedAmt == 0) { continue; } // get the token's staking ratio against ex-staked amount tokenSR = stakedAmt.divideDecimal(exEA); // get unstake amount unstakAmt = _preciseMulToDecimal(_amount, tokenSR); unstakAmt = unstakAmt.add(remainAmount); // get remain amount and cap unstakAmt within stakedAmt (remainAmount, unstakAmt) = unstakAmt > stakedAmt ? (unstakAmt.sub(stakedAmt), stakedAmt) : (0, unstakAmt); // convert the unstake amount to the token amount unstakAmt = _toCurrency(_unitKey, keys[i], unstakAmt); // get the token's decimals decimals = stakingState.tokenDecimals(keys[i]); if (uint(18) > decimals) { // save unstakAmt to tokenSR tokenSR = unstakAmt; // round down the unstake amount unstakAmt = unstakAmt.roundDownDecimal(uint(18).sub(decimals)); // update remainAmount tokenSR = tokenSR.sub(unstakAmt); tokenSR = _toCurrency(keys[i], _unitKey, tokenSR); remainAmount = remainAmount.add(tokenSR); minDecimals = minDecimals > decimals ? decimals : minDecimals; } // unstake the token and refund it to the staker/liquidator _unstakeAndRefund(_staker, _taker, unstakAmt, keys[i]); } remainAmount = minDecimals < 18 && remainAmount > 10**(18 - minDecimals) ? remainAmount : 0; } /** * @notice It unstakes multiple tokens by pre-defined order. * * @param _staker staker address * @param _existDebt existing debt amount * @param _periCol Peri Collateral amount */ function unstakeToFitTR( address _staker, uint _existDebt, uint _periCol ) external onlyIssuer returns (uint burnAmt) { // bytes32[] memory currencyKeys = stakingState.getTokenCurrencyKeys(); // get the order of unstaking // bytes32[] memory order; // if (!_keyChecker(currencyKeys, currencyKeyOrder)) { // order = currencyKeys; // } else { // order = currencyKeyOrder; // } /* // set the currency key order if currencyKeyOrder is not set bytes32[] memory order = stakingState.getTokenCurrencyKeys(); if (_keyChecker(order, currencyKeyOrder)) { order = currencyKeyOrder; } // get the staker's total staked amount in unit currency uint combinedAmount = _combinedStakedAmountOf(_staker, _unitKey); require(_combinedStakedAmountOf(_staker, _unitKey) >= _amount, "Combined staked amount is not enough"); uint[] memory unsakingAmts = new uint[](order.length); for (uint i = 0; i < order.length; i++) { // get the staked amount of the token uint stakedAmt = stakingState.stakedAmountOf(order[i], _staker); // Becacuse of exchange rate calculation error, // remained unstaking debt amount is converted into each currency rather than converting staked amount. uint unstakingAmt = _toCurrency(_unitKey, order[i], _amount); // If the token amount is smaller than amount to be unstaked, if (stakedAmt < unstakingAmt) { // set the token amount to the amount to be unstaked. unsakingAmts[i] = stakedAmt; // subtract the amount to be unstaked by the token amount // convert remained unstaking amount into unit currency and set it to _amount _amount = _toCurrency(order[i], _unitKey, unstakingAmt.sub(stakedAmt)); } else { unsakingAmts[i] = unstakingAmt; _amount = 0; } // unstake the token and refund it to the staker _unstakeAndRefund(_staker, _staker, (_amount > 0 ? stakedAmt : unstakingAmt), order[i]); // if the amount to be unstaked is 0, break the loop if (_amount == 0) { break; } }*/ uint exRefundAmt; uint exEA; (burnAmt, exRefundAmt, exEA) = _burnAmtToFitTR(_staker, _existDebt, _periCol); require(burnAmt != 0 || exRefundAmt != 0, "Account is already claimable"); if (exRefundAmt != 0) { _proRataUnstake(_staker, _staker, exRefundAmt, exEA, pUSD); } // _initTargetRatios(_staker, _existDebt.sub(_amount).add(remainAmt)); // for (uint i = 0; i < order.length; i++) { // if (unsakingAmts[i] == 0) { // continue; // } // _unstakeAndRefund(_staker, _staker, unsakingAmts[i], order[i]); // } } /** * @notice unstakes tokens and refund it to the staker or liquidator. * * @param _unstaker staker address * @param _liquidator liquidator or staker address * @param _amount amount to get unstaked in unit currency * @param _targetKey the currency unit of _amount * */ function _unstakeAndRefund( address _unstaker, address _liquidator, uint _amount, bytes32 _targetKey ) internal tokenRegistered(_targetKey) { uint targetDecimals = stakingState.tokenDecimals(_targetKey); require(targetDecimals <= 18, "Invalid decimal number"); // We don't have to round up for staking or unstaking amount. // uint unstakingAmountConvertedRoundedUp = _amount.roundUpDecimal(uint(18).sub(targetDecimals)); uint floorUnstakingAmount = _amount.roundDownDecimal(uint(18).sub(targetDecimals)); // stakingState.unstake(_targetKey, _unstaker, unstakingAmountConvertedRoundedUp); stakingState.unstake(_targetKey, _unstaker, floorUnstakingAmount); require( // stakingState.refund(_targetKey, _liquidator, unstakingAmountConvertedRoundedUp), stakingState.refund(_targetKey, _liquidator, floorUnstakingAmount), "Refund has been failed" ); } /** * @notice Sets stakingState contract address * * @param _stakingState stakingState contract address */ function setStakingState(address _stakingState) external onlyOwner { stakingState = IStakingState(_stakingState); } /** * @notice unstakes all tokens and refund it to the staker. * * @param _from address of staker */ function exit(address _from) external onlyIssuer { bytes32[] memory tokenList = stakingState.getTokenCurrencyKeys(); for (uint i; i < tokenList.length; i++) { uint stakedAmount = _stakedAmountOf(_from, tokenList[i], tokenList[i]); if (stakedAmount == 0) { continue; } _unstakeAndRefund(_from, _from, stakedAmount, tokenList[i]); } // stakingState.setTargetRatio(_from, getIssuanceRatio()); // stakingState.setExTargetRatio(_from, 0); } function _requireOverIssuanceRatio(uint _tRatio) internal view { require(_tRatio.roundDownDecimal(uint(12)) <= getExternalTokenQuota(), "Over max external quota"); } function _requireRatesNotInvalid(bool anyRateIsInvalid) internal pure { require(!anyRateIsInvalid, "A pynth or a external token rate is invalid"); } function _onlyIssuer() internal view { require(msg.sender == address(issuer()), "Sender is not Issuer"); } function _onlyLiquidations() internal view { require(msg.sender == address(liquidations()), "Sender is not Liquidations"); } function _tokenRegistered(bytes32 _currencyKey) internal view { require(stakingState.tokenAddress(_currencyKey) != address(0), "Target token is not registered"); } modifier onlyIssuer() { _onlyIssuer(); _; } modifier onlyLiquidations() { _onlyLiquidations(); _; } modifier tokenRegistered(bytes32 _currencyKey) { _tokenRegistered(_currencyKey); _; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_stakingState","type":"address"},{"internalType":"address","name":"_resolver","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"name","type":"bytes32"},{"indexed":false,"internalType":"address","name":"destination","type":"address"}],"name":"CacheUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"constant":true,"inputs":[],"name":"CONTRACT_NAME","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_existDebt","type":"uint256"},{"internalType":"uint256","name":"_periCol","type":"uint256"}],"name":"burnAmtToFitTR","outputs":[{"internalType":"uint256","name":"burnAmount","type":"uint256"},{"internalType":"uint256","name":"exRefundAmt","type":"uint256"},{"internalType":"uint256","name":"exEA","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"bytes32","name":"_unitCurrency","type":"bytes32"}],"name":"combinedStakedAmountOf","outputs":[{"internalType":"uint256","name":"combinedSA","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_existDebt","type":"uint256"}],"name":"exStakingRatio","outputs":[{"internalType":"uint256","name":"exSR","type":"uint256"},{"internalType":"uint256","name":"maxSR","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_from","type":"address"}],"name":"exit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getExDebt","outputs":[{"internalType":"uint256","name":"exDebt","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getExEADebt","outputs":[{"internalType":"uint256","name":"exDebt","type":"uint256"},{"internalType":"uint256","name":"exEA","type":"uint256"},{"internalType":"uint256","name":"exTRatio","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"existDebt","type":"uint256"},{"internalType":"uint256","name":"periCol","type":"uint256"}],"name":"getRatios","outputs":[{"internalType":"uint256","name":"tRatio","type":"uint256"},{"internalType":"uint256","name":"cRatio","type":"uint256"},{"internalType":"uint256","name":"exTRatio","type":"uint256"},{"internalType":"uint256","name":"exEA","type":"uint256"},{"internalType":"uint256","name":"exSR","type":"uint256"},{"internalType":"uint256","name":"maxSR","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_existDebt","type":"uint256"}],"name":"getTargetRatio","outputs":[{"internalType":"uint256","name":"tRatio","type":"uint256"},{"internalType":"uint256","name":"exTRatio","type":"uint256"},{"internalType":"uint256","name":"exEA","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"_currencyKey","type":"bytes32"}],"name":"getTokenActivation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"_currencyKey","type":"bytes32"}],"name":"getTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"_currencyKey","type":"bytes32"}],"name":"getTokenDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getTokenList","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"bytes32","name":"_currencyKey","type":"bytes32"}],"name":"getTokenPUSDValueOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isResolverCached","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_existDebt","type":"uint256"},{"internalType":"uint256","name":"_periCol","type":"uint256"},{"internalType":"bytes32","name":"_targetKey","type":"bytes32"}],"name":"maxStakableAmountOf","outputs":[{"internalType":"uint256","name":"maxAmount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bytes32","name":"_targetKey","type":"bytes32"}],"name":"otherTokenIREA","outputs":[{"internalType":"uint256","name":"otherIR","type":"uint256"},{"internalType":"uint256","name":"otherEA","type":"uint256"},{"internalType":"uint256","name":"tokenIR","type":"uint256"},{"internalType":"uint256","name":"tokenEA","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32","name":"_unitKey","type":"bytes32"}],"name":"proRataUnstake","outputs":[{"internalType":"uint256","name":"remainAmt","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"rebuildCache","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_liquidator","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"remainAmt","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"resolver","outputs":[{"internalType":"contract AddressResolver","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"resolverAddressesRequired","outputs":[{"internalType":"bytes32[]","name":"addresses","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_stakingState","type":"address"}],"name":"setStakingState","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"setupExpiryTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_existDebt","type":"uint256"},{"internalType":"uint256","name":"_periCol","type":"uint256"},{"internalType":"bytes32","name":"_targetKey","type":"bytes32"},{"internalType":"bytes32","name":"_unitKey","type":"bytes32"}],"name":"stake","outputs":[{"internalType":"uint256","name":"debtChange","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_existDebt","type":"uint256"},{"internalType":"uint256","name":"_periCol","type":"uint256"},{"internalType":"bytes32","name":"_targetKey","type":"bytes32"}],"name":"stakeToMaxExQuota","outputs":[{"internalType":"uint256","name":"debtChange","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"bytes32","name":"_currencyKey","type":"bytes32"},{"internalType":"bytes32","name":"_unitCurrency","type":"bytes32"}],"name":"stakedAmountOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"stakingState","outputs":[{"internalType":"contract IStakingState","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"tokenStakeStatus","outputs":[{"internalType":"bytes32[]","name":"tokenList","type":"bytes32[]"},{"internalType":"uint256[]","name":"stakedAmts","type":"uint256[]"},{"internalType":"uint256[]","name":"decimals","type":"uint256[]"},{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes32","name":"_targetKey","type":"bytes32"},{"internalType":"bytes32","name":"_unitKey","type":"bytes32"}],"name":"unstake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_existDebt","type":"uint256"},{"internalType":"uint256","name":"_periCol","type":"uint256"}],"name":"unstakeToFitTR","outputs":[{"internalType":"uint256","name":"burnAmt","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50604051620041ed380380620041ed8339818101604052606081101561003557600080fd5b50805160208201516040909201519091906249d4008180856001600160a01b0381166100a8576040805162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b038316908117825560408051928352602083019190915280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a150600280546001600160a01b039283166001600160a01b031991821617909155429093016004556005805495909116949092169390931790555050506140a1806200014c6000396000f3fe608060405234801561001057600080fd5b50600436106102415760003560e01c80637a84b61711610145578063b42652e9116100bd578063e082f1d41161008c578063f5faf9bd11610071578063f5faf9bd14610865578063ff18cf46146108b7578063ffb0a081146108ea57610241565b8063e082f1d4146107f8578063ede459561461080057610241565b8063b42652e914610631578063c23d798114610657578063c70cc960146107a0578063dac6e576146107c657610241565b80639c1b38f711610114578063ad47ffc5116100f9578063ad47ffc5146105aa578063b12e4410146105dc578063b23e5053146105f957610241565b80639c1b38f714610558578063a4678bd21461057e57610241565b80637a84b617146104e45780637d52c4ec14610510578063899ffef4146105485780638da5cb5b1461055057610241565b806353a47bb7116101d8578063614d08f8116101a75780636446406c1161018c5780636446406c1461049c57806374185360146104d457806379ba5097146104dc57610241565b8063614d08f81461046257806362197d9a1461046a57610241565b806353a47bb7146103d55780635abebd07146103dd5780635b6f39791461040f5780635c833bfd1461042c57610241565b8063273cbaa011610214578063273cbaa0146102fd5780632af64bd3146103555780633b1cd52b1461037157806346ba2d90146103bb57610241565b806304f3bcec146102465780630fc3fc8c1461026a5780631627540c146102925780631982de22146102b8575b600080fd5b61024e61092e565b604080516001600160a01b039092168252519081900360200190f35b6102906004803603602081101561028057600080fd5b50356001600160a01b031661093d565b005b610290600480360360208110156102a857600080fd5b50356001600160a01b0316610974565b6102e4600480360360408110156102ce57600080fd5b506001600160a01b0381351690602001356109dd565b6040805192835260208301919091528051918290030190f35b610305610a0e565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610341578181015183820152602001610329565b505050509050019250505060405180910390f35b61035d610b22565b604080519115158252519081900360200190f35b61039d6004803603604081101561038757600080fd5b506001600160a01b038135169060200135610c45565b60408051938452602084019290925282820152519081900360600190f35b6103c3610c63565b60408051918252519081900360200190f35b61024e610c69565b61039d600480360360608110156103f357600080fd5b506001600160a01b038135169060208101359060400135610c78565b61035d6004803603602081101561042557600080fd5b5035610c98565b6103c36004803603606081101561044257600080fd5b506001600160a01b03813581169160208101359160409091013516610d2f565b6103c3610da2565b6103c36004803603606081101561048057600080fd5b506001600160a01b038135169060208101359060400135610dc6565b6103c3600480360360808110156104b257600080fd5b506001600160a01b038135169060208101359060408101359060600135610e68565b610290610f02565b6102906110f0565b6103c3600480360360408110156104fa57600080fd5b506001600160a01b0381351690602001356111b9565b6103c36004803603608081101561052657600080fd5b506001600160a01b0381351690602081013590604081013590606001356111ce565b6103056111e9565b61024e6112a1565b6103c36004803603602081101561056e57600080fd5b50356001600160a01b03166112b0565b6103c36004803603604081101561059457600080fd5b506001600160a01b0381351690602001356112bb565b6103c3600480360360608110156105c057600080fd5b506001600160a01b0381351690602081013590604001356112c7565b61024e600480360360208110156105f257600080fd5b50356112de565b6102906004803603608081101561060f57600080fd5b506001600160a01b03813516906020810135906040810135906060013561132a565b6102906004803603602081101561064757600080fd5b50356001600160a01b0316611362565b61067d6004803603602081101561066d57600080fd5b50356001600160a01b03166114f4565b6040518080602001806020018060200180602001858103855289818151815260200191508051906020019060200280838360005b838110156106c95781810151838201526020016106b1565b50505050905001858103845288818151815260200191508051906020019060200280838360005b838110156107085781810151838201526020016106f0565b50505050905001858103835287818151815260200191508051906020019060200280838360005b8381101561074757818101518382015260200161072f565b50505050905001858103825286818151815260200191508051906020019060200280838360005b8381101561078657818101518382015260200161076e565b505050509050019850505050505050505060405180910390f35b61039d600480360360208110156107b657600080fd5b50356001600160a01b03166118d8565b6103c3600480360360608110156107dc57600080fd5b506001600160a01b0381351690602081013590604001356118f3565b61024e611960565b6108326004803603606081101561081657600080fd5b506001600160a01b03813516906020810135906040013561196f565b604080519687526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190f35b6108916004803603604081101561087b57600080fd5b506001600160a01b038135169060200135611999565b604080519485526020850193909352838301919091526060830152519081900360800190f35b6108d4600480360360208110156108cd57600080fd5b50356119ba565b6040805160ff9092168252519081900360200190f35b6103c3600480360360c081101561090057600080fd5b506001600160a01b038135169060208101359060408101359060608101359060808101359060a00135611a06565b6002546001600160a01b031681565b610945611a45565b6005805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b61097c611a45565b600180546001600160a01b03831673ffffffffffffffffffffffffffffffffffffffff19909116811790915560408051918252517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229181900360200190a150565b60008060008060006109ee87611a90565b925092509250610a0086848484611b6d565b945094505050509250929050565b60055460408051635b08123760e01b815290516060926001600160a01b031691635b081237916004808301926000929190829003018186803b158015610a5357600080fd5b505afa158015610a67573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610a9057600080fd5b8101908080516040519392919084640100000000821115610ab057600080fd5b908301906020820185811115610ac557600080fd5b8251866020820283011164010000000082111715610ae257600080fd5b82525081516020918201928201910280838360005b83811015610b0f578181015183820152602001610af7565b5050505090500160405250505090505b90565b60006060610b2e6111e9565b905060005b8151811015610c3c576000828281518110610b4a57fe5b6020908102919091018101516000818152600383526040908190205460025482517f21f8a7210000000000000000000000000000000000000000000000000000000081526004810185905292519395506001600160a01b03918216949116926321f8a721926024808201939291829003018186803b158015610bcb57600080fd5b505afa158015610bdf573d6000803e3d6000fd5b505050506040513d6020811015610bf557600080fd5b50516001600160a01b0316141580610c2257506000818152600360205260409020546001600160a01b0316155b15610c335760009350505050610b1f565b50600101610b33565b50600191505090565b6000806000610c548585611c17565b50929891975095509350505050565b60045481565b6001546001600160a01b031681565b6000806000610c88868686611d94565b9250925092505b93509350939050565b600554604080517f8547dbd90000000000000000000000000000000000000000000000000000000081526004810184905290516000926001600160a01b031691638547dbd9916024808301926020929190829003018186803b158015610cfd57600080fd5b505afa158015610d11573d6000803e3d6000fd5b505050506040513d6020811015610d2757600080fd5b505192915050565b6000610d39611fa7565b6000610d4c85631c1554d160e21b612014565b9050808411610d5d57836000610d6e565b80610d6e858263ffffffff61218e16565b9094509150610d8785848684631c1554d160e21b6121eb565b9050610d99828263ffffffff61252316565b95945050505050565b7f45787465726e616c546f6b656e5374616b654d616e616765720000000000000081565b6000610dd061257d565b600080610dde868686611d94565b9194509250905082151580610df257508115155b610e43576040805162461bcd60e51b815260206004820152601c60248201527f4163636f756e7420697320616c726561647920636c61696d61626c6500000000604482015290519081900360640190fd5b8115610e5f57610e5d86878484631c1554d160e21b6121eb565b505b50509392505050565b6000610e7261257d565b600080610e838787600088886125ea565b9094509250905081610edc576040805162461bcd60e51b815260206004820152601f60248201527f4e6f20617661696c61626c652065782d746f6b656e7320746f207374616b6500604482015290519081900360640190fd5b610ee58161290f565b610ef8878386631c1554d160e21b61297e565b5050949350505050565b6060610f0c6111e9565b905060005b81518110156110ec576000828281518110610f2857fe5b602090810291909101810151600254604080517f5265736f6c766572206d697373696e67207461726765743a200000000000000081860152603980820185905282518083039091018152605982018084527fdacb2d01000000000000000000000000000000000000000000000000000000009052605d8201858152607d83019384528151609d84015281519597506000966001600160a01b039095169563dacb2d01958995939492939260bd0191908501908083838c5b83811015610ff7578181015183820152602001610fdf565b50505050905090810190601f1680156110245780820380516001836020036101000a031916815260200191505b50935050505060206040518083038186803b15801561104257600080fd5b505afa158015611056573d6000803e3d6000fd5b505050506040513d602081101561106c57600080fd5b5051600083815260036020908152604091829020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03851690811790915582518681529182015281519293507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa68929081900390910190a15050600101610f11565b5050565b6001546001600160a01b031633146111395760405162461bcd60e51b8152600401808060200182810382526035815260200180613f726035913960400191505060405180910390fd5b600054600154604080516001600160a01b03938416815292909116602083015280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a1600180546000805473ffffffffffffffffffffffffffffffffffffffff199081166001600160a01b03841617909155169055565b60006111c58383612014565b90505b92915050565b60006111de8585600086866125ea565b979650505050505050565b6060806111f4612c22565b60408051600380825260808201909252919250606091906020820183803883390190505090506524b9b9bab2b960d11b8160008151811061123157fe5b6020026020010181815250506c45786368616e6765526174657360981b8160018151811061125b57fe5b6020026020010181815250506b4c69717569646174696f6e7360a01b8160028151811061128457fe5b60200260200101818152505061129a8282612c81565b9250505090565b6000546001600160a01b031681565b60006111c882612d3d565b60006111c58383612d5a565b60006112d4848484612e59565b90505b9392505050565b600554604080516397bb3ce960e01b81526004810184905290516000926001600160a01b0316916397bb3ce9916024808301926020929190829003018186803b158015610cfd57600080fd5b61133261257d565b6113448361133f84612f1d565b612fd1565b925061135c8485611356848688613002565b85613068565b50505050565b61136a61257d565b60055460408051635b08123760e01b815290516060926001600160a01b031691635b081237916004808301926000929190829003018186803b1580156113af57600080fd5b505afa1580156113c3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156113ec57600080fd5b810190808051604051939291908464010000000082111561140c57600080fd5b90830190602082018581111561142157600080fd5b825186602082028301116401000000008211171561143e57600080fd5b82525081516020918201928201910280838360005b8381101561146b578181015183820152602001611453565b50505050905001604052505050905060005b81518110156114ef5760006114b98484848151811061149857fe5b60200260200101518585815181106114ac57fe5b6020026020010151612e59565b9050806114c657506114e7565b6114e58485838686815181106114d857fe5b6020026020010151613068565b505b60010161147d565b505050565b606080606080600560009054906101000a90046001600160a01b03166001600160a01b0316635b0812376040518163ffffffff1660e01b815260040160006040518083038186803b15801561154857600080fd5b505afa15801561155c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561158557600080fd5b81019080805160405193929190846401000000008211156115a557600080fd5b9083019060208201858111156115ba57600080fd5b82518660208202830111640100000000821117156115d757600080fd5b82525081516020918201928201910280838360005b838110156116045781810151838201526020016115ec565b505050509050016040525050509350835160405190808252806020026020018201604052801561163e578160200160208202803883390190505b509250835160405190808252806020026020018201604052801561166c578160200160208202803883390190505b509150835160405190808252806020026020018201604052801561169a578160200160208202803883390190505b50905060005b84518110156118d05760055485516001600160a01b039091169063480310bb908790849081106116cc57fe5b6020026020010151886040518363ffffffff1660e01b815260040180838152602001826001600160a01b03166001600160a01b031681526020019250505060206040518083038186803b15801561172257600080fd5b505afa158015611736573d6000803e3d6000fd5b505050506040513d602081101561174c57600080fd5b5051845185908390811061175c57fe5b602090810291909101015260055485516001600160a01b03909116906344aedc5f9087908490811061178a57fe5b60200260200101516040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156117c657600080fd5b505afa1580156117da573d6000803e3d6000fd5b505050506040513d60208110156117f057600080fd5b5051835160ff9091169084908390811061180657fe5b60200260200101818152505061182e85828151811061182157fe5b60200260200101516132f3565b6001600160a01b03166370a08231876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561188357600080fd5b505afa158015611897573d6000803e3d6000fd5b505050506040513d60208110156118ad57600080fd5b505182518390839081106118bd57fe5b60209081029190910101526001016116a0565b509193509193565b60008060006118e684611a90565b9196909550909350915050565b60008060008061190287611a90565b925092509250858310156119475760405162461bcd60e51b81526004018080602001828103825260218152602001806140226021913960400191505060405180910390fd5b6119518682612fd1565b95506111de87888885896121eb565b6005546001600160a01b031681565b600080600080600080611983898989613380565b949e939d50919b50995097509095509350505050565b6000806000806119a986866133e1565b509299919850965090945092505050565b600554604080516344aedc5f60e01b81526004810184905290516000926001600160a01b0316916344aedc5f916024808301926020929190829003018186803b158015610cfd57600080fd5b6000611a1061257d565b6000611a1f88878988886125ea565b985092509050611a2e8161290f565b611a3a8888868661297e565b509695505050505050565b6000546001600160a01b03163314611a8e5760405162461bcd60e51b815260040180806020018281038252602f815260200180613fd2602f913960400191505060405180910390fd5b565b6000806000806000806000611aac88635553444360e01b6133e1565b9a5092965090945092509050611ac8818463ffffffff61252316565b955060008611611b4757736e0bff12512a94f3b1ecebe08203fe7f8f8fae6463907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611b1657600080fd5b505af4158015611b2a573d6000803e3d6000fd5b505050506040513d6020811015611b4057600080fd5b5051611b61565b611b618483611b5c848a63ffffffff61374d16565b613777565b96989597505050505050565b60008083611b8057506000905080611c0e565b6000611b8a6137ef565b90506000868811611b9c576000611bac565b611bac888863ffffffff61218e16565b9050611bb88183612fd1565b9050611bca818763ffffffff61252316565b9050611bdc868263ffffffff61374d16565b9350611c09611bf983611bed6138a6565b9063ffffffff61218e16565b61133f878563ffffffff61218e16565b925050505b94509492505050565b60008080808085611cae57611c2a6137ef565b736e0bff12512a94f3b1ecebe08203fe7f8f8fae6463907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611c6e57600080fd5b505af4158015611c82573d6000803e3d6000fd5b505050506040513d6020811015611c9857600080fd5b5051909550935060009250829150819050611d8a565b6000611cb988611a90565b9650945090506000611cc96137ef565b905084611d585780736e0bff12512a94f3b1ecebe08203fe7f8f8fae6463907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611d1557600080fd5b505af4158015611d29573d6000803e3d6000fd5b505050506040513d6020811015611d3f57600080fd5b5051909750955060009450849350839250611d8a915050565b611d6488838789611b6d565b9094509250828411611d765783611d78565b825b9150611d85818784613777565b965050505b9295509295909350565b6000806000806000611da588611a90565b909450909250905082611df457611dc386611dbe6137ef565b61392c565b9150818711611dd3576000611de3565b611de3878363ffffffff61218e16565b945060009350839250610c8f915050565b6000611dfe6137ef565b90506000611e0a6138a6565b90506000611e31611e21838563ffffffff61218e16565b61133f868663ffffffff61218e16565b90506000611e3f8b84612fd1565b9050611e4b818361392c565b90506000611e598b8661392c565b90506000828911611e7957611e748d8963ffffffff61218e16565b611e93565b611e93611e86848961392c565b8e9063ffffffff61218e16565b905081811115611f7657611f2a611eaa8d8661392c565b61133f86736e0bff12512a94f3b1ecebe08203fe7f8f8fae6463907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611ef257600080fd5b505af4158015611f06573d6000803e3d6000fd5b505050506040513d6020811015611f1c57600080fd5b50519063ffffffff61218e16565b9250611f53838a11611f3c5788611f46565b611f46848961392c565b839063ffffffff61252316565b9750878d11611f63576000611f73565b611f738d8963ffffffff61218e16565b9a505b828911611f84576000611f94565b611f94898463ffffffff61218e16565b9950505050505050505093509350939050565b611faf61394a565b6001600160a01b0316336001600160a01b031614611a8e576040805162461bcd60e51b815260206004820152601a60248201527f53656e646572206973206e6f74204c69717569646174696f6e73000000000000604482015290519081900360640190fd5b60006060600560009054906101000a90046001600160a01b03166001600160a01b0316635b0812376040518163ffffffff1660e01b815260040160006040518083038186803b15801561206657600080fd5b505afa15801561207a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156120a357600080fd5b81019080805160405193929190846401000000008211156120c357600080fd5b9083019060208201858111156120d857600080fd5b82518660208202830111640100000000821117156120f557600080fd5b82525081516020918201928201910280838360005b8381101561212257818101518382015260200161210a565b50505050905001604052505050905060005b815181101561218657600061215d8684848151811061214f57fe5b602002602001015187612e59565b90508061216a575061217e565b61217a848263ffffffff61252316565b9350505b600101612134565b505092915050565b6000828211156121e5576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600080600080600080601090506060600560009054906101000a90046001600160a01b03166001600160a01b0316635b0812376040518163ffffffff1660e01b815260040160006040518083038186803b15801561224857600080fd5b505afa15801561225c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561228557600080fd5b81019080805160405193929190846401000000008211156122a557600080fd5b9083019060208201858111156122ba57600080fd5b82518660208202830111640100000000821117156122d757600080fd5b82525081516020918201928201910280838360005b838110156123045781810151838201526020016122ec565b50505050905001604052505050905060005b81518110156124f05761233d8d83838151811061232f57fe5b60200260200101518b612e59565b965086612349576124e8565b612359878b63ffffffff61374d16565b93506123658b8561392c565b9550612377868963ffffffff61252316565b95508686116123885760008661239a565b612398868863ffffffff61218e16565b875b80975081995050506123c0898383815181106123b257fe5b602002602001015188613002565b60055483519197506001600160a01b0316906344aedc5f908490849081106123e457fe5b60200260200101516040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561242057600080fd5b505afa158015612434573d6000803e3d6000fd5b505050506040513d602081101561244a57600080fd5b505160ff16945060128510156124d65785935061247e61247160128763ffffffff61218e16565b879063ffffffff61396916565b9550612490848763ffffffff61218e16565b93506124b08282815181106124a157fe5b60200260200101518a86613002565b93506124c2888563ffffffff61252316565b97508483116124d157826124d3565b845b92505b6124e88d8d888585815181106114d857fe5b600101612316565b50601282108015612506575081601203600a0a87115b612511576000612513565b865b9c9b505050505050505050505050565b6000828201838110156111c5576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b61258561398f565b6001600160a01b0316336001600160a01b031614611a8e576040805162461bcd60e51b815260206004820152601460248201527f53656e646572206973206e6f7420497373756572000000000000000000000000604482015290519081900360640190fd5b6000808086612609576125fb6137ef565b925060009150819050612904565b60008080808061262d8d8a1561261f578a612628565b635553444360e01b5b6133e1565b939850919650945092509050600061264b838663ffffffff61252316565b90506000828e1161265d57600061266d565b61266d8e8463ffffffff61218e16565b90508c15158061267c57508a15155b1561288d578c6126f5576126b36126958d611dbe6137ef565b82116126ac576126a78261133f6137ef565b611f46565b828d612523565b98506126c2858886898d6139a3565b97506126ce8f8c612d5a565b98508789106126dd57876126df565b885b97506126ee88611dbe8d612f1d565b98506127b7565b8c6127038e61133f8e612f1d565b809950819a5050506127b46127a7600560009054906101000a90046001600160a01b03166001600160a01b03166344aedc5f8e6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561276a57600080fd5b505afa15801561277e573d6000803e3d6000fd5b505050506040513d602081101561279457600080fd5b505160129060ff1663ffffffff61218e16565b899063ffffffff61396916565b97505b6127c38c611dbe6137ef565b9b508b81116127d2578861280f565b6127e2818d63ffffffff61218e16565b89116127ef57600061280f565b61280f612802828e63ffffffff61218e16565b8a9063ffffffff61218e16565b9850612821848963ffffffff61252316565b9350612833848763ffffffff61252316565b9150612858612842878961392c565b61284c868861392c565b9063ffffffff61252316565b925061286a8e8a63ffffffff61252316565b9d50828e1161287a57600061288a565b61288a8e8463ffffffff61218e16565b90505b816128a95761289a6137ef565b99506129049650505050505050565b6128b58161133f6137ef565b90506128cc8786611b5c878663ffffffff61374d16565b99506128fa6128d96137ef565b8b611b5c6128ed868663ffffffff61252316565b869063ffffffff61374d16565b9950505050505050505b955095509592505050565b6129176138a6565b61292882600c63ffffffff61396916565b111561297b576040805162461bcd60e51b815260206004820152601760248201527f4f766572206d61782065787465726e616c2071756f7461000000000000000000604482015290519081900360640190fd5b50565b600061298b828486613002565b600554604080516344aedc5f60e01b81526004810187905290519293506000926001600160a01b03909216916344aedc5f91602480820192602092909190829003018186803b1580156129dd57600080fd5b505afa1580156129f1573d6000803e3d6000fd5b505050506040513d6020811015612a0757600080fd5b505160ff1690506012811115612a64576040805162461bcd60e51b815260206004820152601660248201527f496e76616c696420646563696d616c206e756d62657200000000000000000000604482015290519081900360640190fd5b612a7560128263ffffffff61218e16565b9050612a87828263ffffffff61396916565b9150612a92846132f3565b6005546001600160a01b03918216916323b872dd91899116612abe86600a87900a63ffffffff613a8516565b6040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b158015612b2657600080fd5b505af1158015612b3a573d6000803e3d6000fd5b505050506040513d6020811015612b5057600080fd5b5051612b8d5760405162461bcd60e51b815260040180806020018281038252602a815260200180614043602a913960400191505060405180910390fd5b600554604080517f8c610c8d000000000000000000000000000000000000000000000000000000008152600481018790526001600160a01b0389811660248301526044820186905291519190921691638c610c8d91606480830192600092919082900301818387803b158015612c0257600080fd5b505af1158015612c16573d6000803e3d6000fd5b50505050505050505050565b604080516001808252818301909252606091602080830190803883390190505090507f466c657869626c6553746f72616765000000000000000000000000000000000081600081518110612c7257fe5b60200260200101818152505090565b60608151835101604051908082528060200260200182016040528015612cb1578160200160208202803883390190505b50905060005b8351811015612cf357838181518110612ccc57fe5b6020026020010151828281518110612ce057fe5b6020908102919091010152600101612cb7565b5060005b8251811015612d3657828181518110612d0c57fe5b6020026020010151828286510181518110612d2357fe5b6020908102919091010152600101612cf7565b5092915050565b6000612d5082635553444360e01b6133e1565b9695505050505050565b600080612d6683613aef565b90506000612d73846132f3565b90506000612e47612db6836001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561276a57600080fd5b600a0a836001600160a01b03166370a08231896040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015612e0f57600080fd5b505afa158015612e23573d6000803e3d6000fd5b505050506040513d6020811015612e3957600080fd5b50519063ffffffff613b7d16565b9050612d50818463ffffffff613bd616565b600554604080517f480310bb000000000000000000000000000000000000000000000000000000008152600481018590526001600160a01b0386811660248301529151600093929092169163480310bb91604480820192602092909190829003018186803b158015612eca57600080fd5b505afa158015612ede573d6000803e3d6000fd5b505050506040513d6020811015612ef457600080fd5b5051905080612f05575060006112d7565b81831415612f12576112d7565b6112d4838383613002565b6000612f27613c00565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7f6578546f6b656e49737375616e6365526174696f000000000000000000000000856040516020018083815260200182815260200192505050604051602081830303815290604052805190602001206040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b158015610cfd57600080fd5b6000811580612fde575082155b612ff957612ff4612fef8484613c2b565b613c5d565b6111c5565b50600092915050565b6000828414156130135750806112d7565b50806000631c1554d160e21b851461303d5761302e85613aef565b905061303a838261392c565b91505b631c1554d160e21b84146130605761305484613aef565b9050610d998282612fd1565b509392505050565b8061307281613c7f565b600554604080516344aedc5f60e01b81526004810185905290516000926001600160a01b0316916344aedc5f916024808301926020929190829003018186803b1580156130be57600080fd5b505afa1580156130d2573d6000803e3d6000fd5b505050506040513d60208110156130e857600080fd5b505160ff1690506012811115613145576040805162461bcd60e51b815260206004820152601660248201527f496e76616c696420646563696d616c206e756d62657200000000000000000000604482015290519081900360640190fd5b600061316861315b60128463ffffffff61218e16565b869063ffffffff61396916565b600554604080517fa98b9ff4000000000000000000000000000000000000000000000000000000008152600481018890526001600160a01b038b8116602483015260448201859052915193945091169163a98b9ff49160648082019260009290919082900301818387803b1580156131df57600080fd5b505af11580156131f3573d6000803e3d6000fd5b5050600554604080517f4020ed14000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b038b81166024830152604482018790529151919092169350634020ed14925060648083019260209291908290030181600087803b15801561326d57600080fd5b505af1158015613281573d6000803e3d6000fd5b505050506040513d602081101561329757600080fd5b50516132ea576040805162461bcd60e51b815260206004820152601660248201527f526566756e6420686173206265656e206661696c656400000000000000000000604482015290519081900360640190fd5b50505050505050565b6000816132ff81613c7f565b600554604080516397bb3ce960e01b81526004810186905290516001600160a01b03909216916397bb3ce991602480820192602092909190829003018186803b15801561334b57600080fd5b505afa15801561335f573d6000803e3d6000fd5b505050506040513d602081101561337557600080fd5b505191505b50919050565b6000806000806000806133938989611c17565b93995091965094509250905060006133b1888563ffffffff61252316565b9050600081116133c25760006133d2565b6133d2898263ffffffff61374d16565b95505093975093979195509350565b60008060008060006133f286612f1d565b60055460408051635b08123760e01b8152905192955060129283926060926001600160a01b0390911691635b08123791600480820192600092909190829003018186803b15801561344257600080fd5b505afa158015613456573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561347f57600080fd5b810190808051604051939291908464010000000082111561349f57600080fd5b9083019060208201858111156134b457600080fd5b82518660208202830111640100000000821117156134d157600080fd5b82525081516020918201928201910280838360005b838110156134fe5781810151838201526020016134e6565b50505050905001604052505050905060005b81518110156136f25761353e8b83838151811061352957fe5b6020026020010151631c1554d160e21b612e59565b945061355c82828151811061354f57fe5b6020026020010151612f1d565b87146136315761357182828151811061354f57fe5b9850841561362c57613589888663ffffffff61252316565b60055483519199506001600160a01b0316906344aedc5f908490849081106135ad57fe5b60200260200101516040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156135e957600080fd5b505afa1580156135fd573d6000803e3d6000fd5b505050506040513d602081101561361357600080fd5b505160ff1694508483106136275784613629565b825b92505b6136ea565b84156136ea57613647868663ffffffff61252316565b60055483519197506001600160a01b0316906344aedc5f9084908490811061366b57fe5b60200260200101516040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156136a757600080fd5b505afa1580156136bb573d6000803e3d6000fd5b505050506040513d60208110156136d157600080fd5b505160ff1694508484106136e557846136e7565b835b93505b600101613510565b5061373e61372061370a60128563ffffffff61218e16565b6137148a8c61392c565b9063ffffffff61396916565b61284c61373460128763ffffffff61218e16565b613714898b61392c565b93505050509295509295909350565b60006111c58261376b85670de0b6b3a764000063ffffffff613b7d16565b9063ffffffff613a8516565b600080600084861161379a57613793858763ffffffff61218e16565b60006137ad565b6137aa868663ffffffff61218e16565b60015b91509150806137d5576137d06137c3838661392c565b879063ffffffff61252316565b612d50565b612d506137e2838661392c565b879063ffffffff61218e16565b60006137f9613c00565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7f69737375616e6365526174696f000000000000000000000000000000000000006040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b15801561387557600080fd5b505afa158015613889573d6000803e3d6000fd5b505050506040513d602081101561389f57600080fd5b5051905090565b60006138b0613c00565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7f65787465726e616c546f6b656e51756f746100000000000000000000000000006040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b15801561387557600080fd5b6000811580613939575082155b612ff957612ff4612fef8484613d53565b60006139646b4c69717569646174696f6e7360a01b613d85565b905090565b60006111c5600a83900a613983858263ffffffff613a8516565b9063ffffffff613b7d16565b60006139646524b9b9bab2b960d11b613d85565b6000806139ae6137ef565b905060006139ba6138a6565b905060006139ce898463ffffffff61218e16565b90506139da818861392c565b9350613a04600089116139ee5760006139fe565b6139fe898563ffffffff61218e16565b8761392c565b9050613a16848263ffffffff61252316565b9350613a28828463ffffffff61218e16565b9050613a34818661392c565b905083811015613a4a5760009350505050610d99565b613a5a818563ffffffff61218e16565b9350613a6c898363ffffffff61218e16565b9050613a788482612fd1565b9998505050505050505050565b6000808211613adb576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b6000828481613ae657fe5b04949350505050565b600080613afa613e6e565b6001600160a01b0316630c71cd23846040518263ffffffff1660e01b815260040180828152602001915050604080518083038186803b158015613b3c57600080fd5b505afa158015613b50573d6000803e3d6000fd5b505050506040513d6040811015613b6657600080fd5b508051602090910151909250905061337a81613e89565b600082613b8c575060006111c8565b82820282848281613b9957fe5b04146111c55760405162461bcd60e51b81526004018080602001828103825260218152602001806140016021913960400191505060405180910390fd5b6000670de0b6b3a7640000613bf1848463ffffffff613b7d16565b81613bf857fe5b049392505050565b60006139647f466c657869626c6553746f726167650000000000000000000000000000000000613d85565b6000811580613c38575082155b612ff957612ff4613c4883613ec6565b613c5185613ec6565b9063ffffffff613edc16565b60006305f5e10082046005600a820610613c7557600a015b600a900492915050565b600554604080516397bb3ce960e01b81526004810184905290516000926001600160a01b0316916397bb3ce9916024808301926020929190829003018186803b158015613ccb57600080fd5b505afa158015613cdf573d6000803e3d6000fd5b505050506040513d6020811015613cf557600080fd5b50516001600160a01b0316141561297b576040805162461bcd60e51b815260206004820152601e60248201527f54617267657420746f6b656e206973206e6f7420726567697374657265640000604482015290519081900360640190fd5b6000811580613d60575082155b612ff957612ff4613d7083613ec6565b613d7985613ec6565b9063ffffffff613ef516565b60008181526003602090815260408083205481517f4d697373696e6720616464726573733a200000000000000000000000000000009381019390935260318084018690528251808503909101815260519093019091526001600160a01b03169081612d365760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613e33578181015183820152602001613e1b565b50505050905090810190601f168015613e605780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60006139646c45786368616e6765526174657360981b613d85565b801561297b5760405162461bcd60e51b815260040180806020018281038252602b815260200180613fa7602b913960400191505060405180910390fd5b60006111c882633b9aca0063ffffffff613b7d16565b60006111c583836b033b2e3c9fd0803ce8000000613f0e565b60006111c583836b033b2e3c9fd0803ce8000000613f46565b600080613f288461376b87600a870263ffffffff613b7d16565b90506005600a825b0610613f3a57600a015b600a9004949350505050565b600080600a8304613f5d868663ffffffff613b7d16565b81613f6457fe5b0490506005600a82613f3056fe596f75206d757374206265206e6f6d696e61746564206265666f726520796f752063616e20616363657074206f776e657273686970412070796e7468206f7220612065787465726e616c20746f6b656e207261746520697320696e76616c69644f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6e536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774e6f7420656e6f7567682065787465726e616c207374616b656420616d6f756e745472616e7366657272696e67207374616b696e6720746f6b656e20686173206265656e206661696c6564a265627a7a72315820cfbd39bfcc87230b5e9aef41175923b35ce6712d42e1c3176bc6b48a8a8ba80164736f6c634300051000320000000000000000000000001c19d81a6f11958d58130ddbc505933426c80369000000000000000000000000263b671648675bda5263525eca554e4d5697e2100000000000000000000000007015cd1e78ba1428d103b0c2513077b2826b64fc
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102415760003560e01c80637a84b61711610145578063b42652e9116100bd578063e082f1d41161008c578063f5faf9bd11610071578063f5faf9bd14610865578063ff18cf46146108b7578063ffb0a081146108ea57610241565b8063e082f1d4146107f8578063ede459561461080057610241565b8063b42652e914610631578063c23d798114610657578063c70cc960146107a0578063dac6e576146107c657610241565b80639c1b38f711610114578063ad47ffc5116100f9578063ad47ffc5146105aa578063b12e4410146105dc578063b23e5053146105f957610241565b80639c1b38f714610558578063a4678bd21461057e57610241565b80637a84b617146104e45780637d52c4ec14610510578063899ffef4146105485780638da5cb5b1461055057610241565b806353a47bb7116101d8578063614d08f8116101a75780636446406c1161018c5780636446406c1461049c57806374185360146104d457806379ba5097146104dc57610241565b8063614d08f81461046257806362197d9a1461046a57610241565b806353a47bb7146103d55780635abebd07146103dd5780635b6f39791461040f5780635c833bfd1461042c57610241565b8063273cbaa011610214578063273cbaa0146102fd5780632af64bd3146103555780633b1cd52b1461037157806346ba2d90146103bb57610241565b806304f3bcec146102465780630fc3fc8c1461026a5780631627540c146102925780631982de22146102b8575b600080fd5b61024e61092e565b604080516001600160a01b039092168252519081900360200190f35b6102906004803603602081101561028057600080fd5b50356001600160a01b031661093d565b005b610290600480360360208110156102a857600080fd5b50356001600160a01b0316610974565b6102e4600480360360408110156102ce57600080fd5b506001600160a01b0381351690602001356109dd565b6040805192835260208301919091528051918290030190f35b610305610a0e565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610341578181015183820152602001610329565b505050509050019250505060405180910390f35b61035d610b22565b604080519115158252519081900360200190f35b61039d6004803603604081101561038757600080fd5b506001600160a01b038135169060200135610c45565b60408051938452602084019290925282820152519081900360600190f35b6103c3610c63565b60408051918252519081900360200190f35b61024e610c69565b61039d600480360360608110156103f357600080fd5b506001600160a01b038135169060208101359060400135610c78565b61035d6004803603602081101561042557600080fd5b5035610c98565b6103c36004803603606081101561044257600080fd5b506001600160a01b03813581169160208101359160409091013516610d2f565b6103c3610da2565b6103c36004803603606081101561048057600080fd5b506001600160a01b038135169060208101359060400135610dc6565b6103c3600480360360808110156104b257600080fd5b506001600160a01b038135169060208101359060408101359060600135610e68565b610290610f02565b6102906110f0565b6103c3600480360360408110156104fa57600080fd5b506001600160a01b0381351690602001356111b9565b6103c36004803603608081101561052657600080fd5b506001600160a01b0381351690602081013590604081013590606001356111ce565b6103056111e9565b61024e6112a1565b6103c36004803603602081101561056e57600080fd5b50356001600160a01b03166112b0565b6103c36004803603604081101561059457600080fd5b506001600160a01b0381351690602001356112bb565b6103c3600480360360608110156105c057600080fd5b506001600160a01b0381351690602081013590604001356112c7565b61024e600480360360208110156105f257600080fd5b50356112de565b6102906004803603608081101561060f57600080fd5b506001600160a01b03813516906020810135906040810135906060013561132a565b6102906004803603602081101561064757600080fd5b50356001600160a01b0316611362565b61067d6004803603602081101561066d57600080fd5b50356001600160a01b03166114f4565b6040518080602001806020018060200180602001858103855289818151815260200191508051906020019060200280838360005b838110156106c95781810151838201526020016106b1565b50505050905001858103845288818151815260200191508051906020019060200280838360005b838110156107085781810151838201526020016106f0565b50505050905001858103835287818151815260200191508051906020019060200280838360005b8381101561074757818101518382015260200161072f565b50505050905001858103825286818151815260200191508051906020019060200280838360005b8381101561078657818101518382015260200161076e565b505050509050019850505050505050505060405180910390f35b61039d600480360360208110156107b657600080fd5b50356001600160a01b03166118d8565b6103c3600480360360608110156107dc57600080fd5b506001600160a01b0381351690602081013590604001356118f3565b61024e611960565b6108326004803603606081101561081657600080fd5b506001600160a01b03813516906020810135906040013561196f565b604080519687526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190f35b6108916004803603604081101561087b57600080fd5b506001600160a01b038135169060200135611999565b604080519485526020850193909352838301919091526060830152519081900360800190f35b6108d4600480360360208110156108cd57600080fd5b50356119ba565b6040805160ff9092168252519081900360200190f35b6103c3600480360360c081101561090057600080fd5b506001600160a01b038135169060208101359060408101359060608101359060808101359060a00135611a06565b6002546001600160a01b031681565b610945611a45565b6005805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055565b61097c611a45565b600180546001600160a01b03831673ffffffffffffffffffffffffffffffffffffffff19909116811790915560408051918252517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229181900360200190a150565b60008060008060006109ee87611a90565b925092509250610a0086848484611b6d565b945094505050509250929050565b60055460408051635b08123760e01b815290516060926001600160a01b031691635b081237916004808301926000929190829003018186803b158015610a5357600080fd5b505afa158015610a67573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015610a9057600080fd5b8101908080516040519392919084640100000000821115610ab057600080fd5b908301906020820185811115610ac557600080fd5b8251866020820283011164010000000082111715610ae257600080fd5b82525081516020918201928201910280838360005b83811015610b0f578181015183820152602001610af7565b5050505090500160405250505090505b90565b60006060610b2e6111e9565b905060005b8151811015610c3c576000828281518110610b4a57fe5b6020908102919091018101516000818152600383526040908190205460025482517f21f8a7210000000000000000000000000000000000000000000000000000000081526004810185905292519395506001600160a01b03918216949116926321f8a721926024808201939291829003018186803b158015610bcb57600080fd5b505afa158015610bdf573d6000803e3d6000fd5b505050506040513d6020811015610bf557600080fd5b50516001600160a01b0316141580610c2257506000818152600360205260409020546001600160a01b0316155b15610c335760009350505050610b1f565b50600101610b33565b50600191505090565b6000806000610c548585611c17565b50929891975095509350505050565b60045481565b6001546001600160a01b031681565b6000806000610c88868686611d94565b9250925092505b93509350939050565b600554604080517f8547dbd90000000000000000000000000000000000000000000000000000000081526004810184905290516000926001600160a01b031691638547dbd9916024808301926020929190829003018186803b158015610cfd57600080fd5b505afa158015610d11573d6000803e3d6000fd5b505050506040513d6020811015610d2757600080fd5b505192915050565b6000610d39611fa7565b6000610d4c85631c1554d160e21b612014565b9050808411610d5d57836000610d6e565b80610d6e858263ffffffff61218e16565b9094509150610d8785848684631c1554d160e21b6121eb565b9050610d99828263ffffffff61252316565b95945050505050565b7f45787465726e616c546f6b656e5374616b654d616e616765720000000000000081565b6000610dd061257d565b600080610dde868686611d94565b9194509250905082151580610df257508115155b610e43576040805162461bcd60e51b815260206004820152601c60248201527f4163636f756e7420697320616c726561647920636c61696d61626c6500000000604482015290519081900360640190fd5b8115610e5f57610e5d86878484631c1554d160e21b6121eb565b505b50509392505050565b6000610e7261257d565b600080610e838787600088886125ea565b9094509250905081610edc576040805162461bcd60e51b815260206004820152601f60248201527f4e6f20617661696c61626c652065782d746f6b656e7320746f207374616b6500604482015290519081900360640190fd5b610ee58161290f565b610ef8878386631c1554d160e21b61297e565b5050949350505050565b6060610f0c6111e9565b905060005b81518110156110ec576000828281518110610f2857fe5b602090810291909101810151600254604080517f5265736f6c766572206d697373696e67207461726765743a200000000000000081860152603980820185905282518083039091018152605982018084527fdacb2d01000000000000000000000000000000000000000000000000000000009052605d8201858152607d83019384528151609d84015281519597506000966001600160a01b039095169563dacb2d01958995939492939260bd0191908501908083838c5b83811015610ff7578181015183820152602001610fdf565b50505050905090810190601f1680156110245780820380516001836020036101000a031916815260200191505b50935050505060206040518083038186803b15801561104257600080fd5b505afa158015611056573d6000803e3d6000fd5b505050506040513d602081101561106c57600080fd5b5051600083815260036020908152604091829020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03851690811790915582518681529182015281519293507f88a93678a3692f6789d9546fc621bf7234b101ddb7d4fe479455112831b8aa68929081900390910190a15050600101610f11565b5050565b6001546001600160a01b031633146111395760405162461bcd60e51b8152600401808060200182810382526035815260200180613f726035913960400191505060405180910390fd5b600054600154604080516001600160a01b03938416815292909116602083015280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a1600180546000805473ffffffffffffffffffffffffffffffffffffffff199081166001600160a01b03841617909155169055565b60006111c58383612014565b90505b92915050565b60006111de8585600086866125ea565b979650505050505050565b6060806111f4612c22565b60408051600380825260808201909252919250606091906020820183803883390190505090506524b9b9bab2b960d11b8160008151811061123157fe5b6020026020010181815250506c45786368616e6765526174657360981b8160018151811061125b57fe5b6020026020010181815250506b4c69717569646174696f6e7360a01b8160028151811061128457fe5b60200260200101818152505061129a8282612c81565b9250505090565b6000546001600160a01b031681565b60006111c882612d3d565b60006111c58383612d5a565b60006112d4848484612e59565b90505b9392505050565b600554604080516397bb3ce960e01b81526004810184905290516000926001600160a01b0316916397bb3ce9916024808301926020929190829003018186803b158015610cfd57600080fd5b61133261257d565b6113448361133f84612f1d565b612fd1565b925061135c8485611356848688613002565b85613068565b50505050565b61136a61257d565b60055460408051635b08123760e01b815290516060926001600160a01b031691635b081237916004808301926000929190829003018186803b1580156113af57600080fd5b505afa1580156113c3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156113ec57600080fd5b810190808051604051939291908464010000000082111561140c57600080fd5b90830190602082018581111561142157600080fd5b825186602082028301116401000000008211171561143e57600080fd5b82525081516020918201928201910280838360005b8381101561146b578181015183820152602001611453565b50505050905001604052505050905060005b81518110156114ef5760006114b98484848151811061149857fe5b60200260200101518585815181106114ac57fe5b6020026020010151612e59565b9050806114c657506114e7565b6114e58485838686815181106114d857fe5b6020026020010151613068565b505b60010161147d565b505050565b606080606080600560009054906101000a90046001600160a01b03166001600160a01b0316635b0812376040518163ffffffff1660e01b815260040160006040518083038186803b15801561154857600080fd5b505afa15801561155c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561158557600080fd5b81019080805160405193929190846401000000008211156115a557600080fd5b9083019060208201858111156115ba57600080fd5b82518660208202830111640100000000821117156115d757600080fd5b82525081516020918201928201910280838360005b838110156116045781810151838201526020016115ec565b505050509050016040525050509350835160405190808252806020026020018201604052801561163e578160200160208202803883390190505b509250835160405190808252806020026020018201604052801561166c578160200160208202803883390190505b509150835160405190808252806020026020018201604052801561169a578160200160208202803883390190505b50905060005b84518110156118d05760055485516001600160a01b039091169063480310bb908790849081106116cc57fe5b6020026020010151886040518363ffffffff1660e01b815260040180838152602001826001600160a01b03166001600160a01b031681526020019250505060206040518083038186803b15801561172257600080fd5b505afa158015611736573d6000803e3d6000fd5b505050506040513d602081101561174c57600080fd5b5051845185908390811061175c57fe5b602090810291909101015260055485516001600160a01b03909116906344aedc5f9087908490811061178a57fe5b60200260200101516040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156117c657600080fd5b505afa1580156117da573d6000803e3d6000fd5b505050506040513d60208110156117f057600080fd5b5051835160ff9091169084908390811061180657fe5b60200260200101818152505061182e85828151811061182157fe5b60200260200101516132f3565b6001600160a01b03166370a08231876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561188357600080fd5b505afa158015611897573d6000803e3d6000fd5b505050506040513d60208110156118ad57600080fd5b505182518390839081106118bd57fe5b60209081029190910101526001016116a0565b509193509193565b60008060006118e684611a90565b9196909550909350915050565b60008060008061190287611a90565b925092509250858310156119475760405162461bcd60e51b81526004018080602001828103825260218152602001806140226021913960400191505060405180910390fd5b6119518682612fd1565b95506111de87888885896121eb565b6005546001600160a01b031681565b600080600080600080611983898989613380565b949e939d50919b50995097509095509350505050565b6000806000806119a986866133e1565b509299919850965090945092505050565b600554604080516344aedc5f60e01b81526004810184905290516000926001600160a01b0316916344aedc5f916024808301926020929190829003018186803b158015610cfd57600080fd5b6000611a1061257d565b6000611a1f88878988886125ea565b985092509050611a2e8161290f565b611a3a8888868661297e565b509695505050505050565b6000546001600160a01b03163314611a8e5760405162461bcd60e51b815260040180806020018281038252602f815260200180613fd2602f913960400191505060405180910390fd5b565b6000806000806000806000611aac88635553444360e01b6133e1565b9a5092965090945092509050611ac8818463ffffffff61252316565b955060008611611b4757736e0bff12512a94f3b1ecebe08203fe7f8f8fae6463907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611b1657600080fd5b505af4158015611b2a573d6000803e3d6000fd5b505050506040513d6020811015611b4057600080fd5b5051611b61565b611b618483611b5c848a63ffffffff61374d16565b613777565b96989597505050505050565b60008083611b8057506000905080611c0e565b6000611b8a6137ef565b90506000868811611b9c576000611bac565b611bac888863ffffffff61218e16565b9050611bb88183612fd1565b9050611bca818763ffffffff61252316565b9050611bdc868263ffffffff61374d16565b9350611c09611bf983611bed6138a6565b9063ffffffff61218e16565b61133f878563ffffffff61218e16565b925050505b94509492505050565b60008080808085611cae57611c2a6137ef565b736e0bff12512a94f3b1ecebe08203fe7f8f8fae6463907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611c6e57600080fd5b505af4158015611c82573d6000803e3d6000fd5b505050506040513d6020811015611c9857600080fd5b5051909550935060009250829150819050611d8a565b6000611cb988611a90565b9650945090506000611cc96137ef565b905084611d585780736e0bff12512a94f3b1ecebe08203fe7f8f8fae6463907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611d1557600080fd5b505af4158015611d29573d6000803e3d6000fd5b505050506040513d6020811015611d3f57600080fd5b5051909750955060009450849350839250611d8a915050565b611d6488838789611b6d565b9094509250828411611d765783611d78565b825b9150611d85818784613777565b965050505b9295509295909350565b6000806000806000611da588611a90565b909450909250905082611df457611dc386611dbe6137ef565b61392c565b9150818711611dd3576000611de3565b611de3878363ffffffff61218e16565b945060009350839250610c8f915050565b6000611dfe6137ef565b90506000611e0a6138a6565b90506000611e31611e21838563ffffffff61218e16565b61133f868663ffffffff61218e16565b90506000611e3f8b84612fd1565b9050611e4b818361392c565b90506000611e598b8661392c565b90506000828911611e7957611e748d8963ffffffff61218e16565b611e93565b611e93611e86848961392c565b8e9063ffffffff61218e16565b905081811115611f7657611f2a611eaa8d8661392c565b61133f86736e0bff12512a94f3b1ecebe08203fe7f8f8fae6463907af6c06040518163ffffffff1660e01b815260040160206040518083038186803b158015611ef257600080fd5b505af4158015611f06573d6000803e3d6000fd5b505050506040513d6020811015611f1c57600080fd5b50519063ffffffff61218e16565b9250611f53838a11611f3c5788611f46565b611f46848961392c565b839063ffffffff61252316565b9750878d11611f63576000611f73565b611f738d8963ffffffff61218e16565b9a505b828911611f84576000611f94565b611f94898463ffffffff61218e16565b9950505050505050505093509350939050565b611faf61394a565b6001600160a01b0316336001600160a01b031614611a8e576040805162461bcd60e51b815260206004820152601a60248201527f53656e646572206973206e6f74204c69717569646174696f6e73000000000000604482015290519081900360640190fd5b60006060600560009054906101000a90046001600160a01b03166001600160a01b0316635b0812376040518163ffffffff1660e01b815260040160006040518083038186803b15801561206657600080fd5b505afa15801561207a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156120a357600080fd5b81019080805160405193929190846401000000008211156120c357600080fd5b9083019060208201858111156120d857600080fd5b82518660208202830111640100000000821117156120f557600080fd5b82525081516020918201928201910280838360005b8381101561212257818101518382015260200161210a565b50505050905001604052505050905060005b815181101561218657600061215d8684848151811061214f57fe5b602002602001015187612e59565b90508061216a575061217e565b61217a848263ffffffff61252316565b9350505b600101612134565b505092915050565b6000828211156121e5576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600080600080600080601090506060600560009054906101000a90046001600160a01b03166001600160a01b0316635b0812376040518163ffffffff1660e01b815260040160006040518083038186803b15801561224857600080fd5b505afa15801561225c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561228557600080fd5b81019080805160405193929190846401000000008211156122a557600080fd5b9083019060208201858111156122ba57600080fd5b82518660208202830111640100000000821117156122d757600080fd5b82525081516020918201928201910280838360005b838110156123045781810151838201526020016122ec565b50505050905001604052505050905060005b81518110156124f05761233d8d83838151811061232f57fe5b60200260200101518b612e59565b965086612349576124e8565b612359878b63ffffffff61374d16565b93506123658b8561392c565b9550612377868963ffffffff61252316565b95508686116123885760008661239a565b612398868863ffffffff61218e16565b875b80975081995050506123c0898383815181106123b257fe5b602002602001015188613002565b60055483519197506001600160a01b0316906344aedc5f908490849081106123e457fe5b60200260200101516040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561242057600080fd5b505afa158015612434573d6000803e3d6000fd5b505050506040513d602081101561244a57600080fd5b505160ff16945060128510156124d65785935061247e61247160128763ffffffff61218e16565b879063ffffffff61396916565b9550612490848763ffffffff61218e16565b93506124b08282815181106124a157fe5b60200260200101518a86613002565b93506124c2888563ffffffff61252316565b97508483116124d157826124d3565b845b92505b6124e88d8d888585815181106114d857fe5b600101612316565b50601282108015612506575081601203600a0a87115b612511576000612513565b865b9c9b505050505050505050505050565b6000828201838110156111c5576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b61258561398f565b6001600160a01b0316336001600160a01b031614611a8e576040805162461bcd60e51b815260206004820152601460248201527f53656e646572206973206e6f7420497373756572000000000000000000000000604482015290519081900360640190fd5b6000808086612609576125fb6137ef565b925060009150819050612904565b60008080808061262d8d8a1561261f578a612628565b635553444360e01b5b6133e1565b939850919650945092509050600061264b838663ffffffff61252316565b90506000828e1161265d57600061266d565b61266d8e8463ffffffff61218e16565b90508c15158061267c57508a15155b1561288d578c6126f5576126b36126958d611dbe6137ef565b82116126ac576126a78261133f6137ef565b611f46565b828d612523565b98506126c2858886898d6139a3565b97506126ce8f8c612d5a565b98508789106126dd57876126df565b885b97506126ee88611dbe8d612f1d565b98506127b7565b8c6127038e61133f8e612f1d565b809950819a5050506127b46127a7600560009054906101000a90046001600160a01b03166001600160a01b03166344aedc5f8e6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561276a57600080fd5b505afa15801561277e573d6000803e3d6000fd5b505050506040513d602081101561279457600080fd5b505160129060ff1663ffffffff61218e16565b899063ffffffff61396916565b97505b6127c38c611dbe6137ef565b9b508b81116127d2578861280f565b6127e2818d63ffffffff61218e16565b89116127ef57600061280f565b61280f612802828e63ffffffff61218e16565b8a9063ffffffff61218e16565b9850612821848963ffffffff61252316565b9350612833848763ffffffff61252316565b9150612858612842878961392c565b61284c868861392c565b9063ffffffff61252316565b925061286a8e8a63ffffffff61252316565b9d50828e1161287a57600061288a565b61288a8e8463ffffffff61218e16565b90505b816128a95761289a6137ef565b99506129049650505050505050565b6128b58161133f6137ef565b90506128cc8786611b5c878663ffffffff61374d16565b99506128fa6128d96137ef565b8b611b5c6128ed868663ffffffff61252316565b869063ffffffff61374d16565b9950505050505050505b955095509592505050565b6129176138a6565b61292882600c63ffffffff61396916565b111561297b576040805162461bcd60e51b815260206004820152601760248201527f4f766572206d61782065787465726e616c2071756f7461000000000000000000604482015290519081900360640190fd5b50565b600061298b828486613002565b600554604080516344aedc5f60e01b81526004810187905290519293506000926001600160a01b03909216916344aedc5f91602480820192602092909190829003018186803b1580156129dd57600080fd5b505afa1580156129f1573d6000803e3d6000fd5b505050506040513d6020811015612a0757600080fd5b505160ff1690506012811115612a64576040805162461bcd60e51b815260206004820152601660248201527f496e76616c696420646563696d616c206e756d62657200000000000000000000604482015290519081900360640190fd5b612a7560128263ffffffff61218e16565b9050612a87828263ffffffff61396916565b9150612a92846132f3565b6005546001600160a01b03918216916323b872dd91899116612abe86600a87900a63ffffffff613a8516565b6040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001836001600160a01b03166001600160a01b031681526020018281526020019350505050602060405180830381600087803b158015612b2657600080fd5b505af1158015612b3a573d6000803e3d6000fd5b505050506040513d6020811015612b5057600080fd5b5051612b8d5760405162461bcd60e51b815260040180806020018281038252602a815260200180614043602a913960400191505060405180910390fd5b600554604080517f8c610c8d000000000000000000000000000000000000000000000000000000008152600481018790526001600160a01b0389811660248301526044820186905291519190921691638c610c8d91606480830192600092919082900301818387803b158015612c0257600080fd5b505af1158015612c16573d6000803e3d6000fd5b50505050505050505050565b604080516001808252818301909252606091602080830190803883390190505090507f466c657869626c6553746f72616765000000000000000000000000000000000081600081518110612c7257fe5b60200260200101818152505090565b60608151835101604051908082528060200260200182016040528015612cb1578160200160208202803883390190505b50905060005b8351811015612cf357838181518110612ccc57fe5b6020026020010151828281518110612ce057fe5b6020908102919091010152600101612cb7565b5060005b8251811015612d3657828181518110612d0c57fe5b6020026020010151828286510181518110612d2357fe5b6020908102919091010152600101612cf7565b5092915050565b6000612d5082635553444360e01b6133e1565b9695505050505050565b600080612d6683613aef565b90506000612d73846132f3565b90506000612e47612db6836001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561276a57600080fd5b600a0a836001600160a01b03166370a08231896040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015612e0f57600080fd5b505afa158015612e23573d6000803e3d6000fd5b505050506040513d6020811015612e3957600080fd5b50519063ffffffff613b7d16565b9050612d50818463ffffffff613bd616565b600554604080517f480310bb000000000000000000000000000000000000000000000000000000008152600481018590526001600160a01b0386811660248301529151600093929092169163480310bb91604480820192602092909190829003018186803b158015612eca57600080fd5b505afa158015612ede573d6000803e3d6000fd5b505050506040513d6020811015612ef457600080fd5b5051905080612f05575060006112d7565b81831415612f12576112d7565b6112d4838383613002565b6000612f27613c00565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7f6578546f6b656e49737375616e6365526174696f000000000000000000000000856040516020018083815260200182815260200192505050604051602081830303815290604052805190602001206040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b158015610cfd57600080fd5b6000811580612fde575082155b612ff957612ff4612fef8484613c2b565b613c5d565b6111c5565b50600092915050565b6000828414156130135750806112d7565b50806000631c1554d160e21b851461303d5761302e85613aef565b905061303a838261392c565b91505b631c1554d160e21b84146130605761305484613aef565b9050610d998282612fd1565b509392505050565b8061307281613c7f565b600554604080516344aedc5f60e01b81526004810185905290516000926001600160a01b0316916344aedc5f916024808301926020929190829003018186803b1580156130be57600080fd5b505afa1580156130d2573d6000803e3d6000fd5b505050506040513d60208110156130e857600080fd5b505160ff1690506012811115613145576040805162461bcd60e51b815260206004820152601660248201527f496e76616c696420646563696d616c206e756d62657200000000000000000000604482015290519081900360640190fd5b600061316861315b60128463ffffffff61218e16565b869063ffffffff61396916565b600554604080517fa98b9ff4000000000000000000000000000000000000000000000000000000008152600481018890526001600160a01b038b8116602483015260448201859052915193945091169163a98b9ff49160648082019260009290919082900301818387803b1580156131df57600080fd5b505af11580156131f3573d6000803e3d6000fd5b5050600554604080517f4020ed14000000000000000000000000000000000000000000000000000000008152600481018990526001600160a01b038b81166024830152604482018790529151919092169350634020ed14925060648083019260209291908290030181600087803b15801561326d57600080fd5b505af1158015613281573d6000803e3d6000fd5b505050506040513d602081101561329757600080fd5b50516132ea576040805162461bcd60e51b815260206004820152601660248201527f526566756e6420686173206265656e206661696c656400000000000000000000604482015290519081900360640190fd5b50505050505050565b6000816132ff81613c7f565b600554604080516397bb3ce960e01b81526004810186905290516001600160a01b03909216916397bb3ce991602480820192602092909190829003018186803b15801561334b57600080fd5b505afa15801561335f573d6000803e3d6000fd5b505050506040513d602081101561337557600080fd5b505191505b50919050565b6000806000806000806133938989611c17565b93995091965094509250905060006133b1888563ffffffff61252316565b9050600081116133c25760006133d2565b6133d2898263ffffffff61374d16565b95505093975093979195509350565b60008060008060006133f286612f1d565b60055460408051635b08123760e01b8152905192955060129283926060926001600160a01b0390911691635b08123791600480820192600092909190829003018186803b15801561344257600080fd5b505afa158015613456573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561347f57600080fd5b810190808051604051939291908464010000000082111561349f57600080fd5b9083019060208201858111156134b457600080fd5b82518660208202830111640100000000821117156134d157600080fd5b82525081516020918201928201910280838360005b838110156134fe5781810151838201526020016134e6565b50505050905001604052505050905060005b81518110156136f25761353e8b83838151811061352957fe5b6020026020010151631c1554d160e21b612e59565b945061355c82828151811061354f57fe5b6020026020010151612f1d565b87146136315761357182828151811061354f57fe5b9850841561362c57613589888663ffffffff61252316565b60055483519199506001600160a01b0316906344aedc5f908490849081106135ad57fe5b60200260200101516040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156135e957600080fd5b505afa1580156135fd573d6000803e3d6000fd5b505050506040513d602081101561361357600080fd5b505160ff1694508483106136275784613629565b825b92505b6136ea565b84156136ea57613647868663ffffffff61252316565b60055483519197506001600160a01b0316906344aedc5f9084908490811061366b57fe5b60200260200101516040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b1580156136a757600080fd5b505afa1580156136bb573d6000803e3d6000fd5b505050506040513d60208110156136d157600080fd5b505160ff1694508484106136e557846136e7565b835b93505b600101613510565b5061373e61372061370a60128563ffffffff61218e16565b6137148a8c61392c565b9063ffffffff61396916565b61284c61373460128763ffffffff61218e16565b613714898b61392c565b93505050509295509295909350565b60006111c58261376b85670de0b6b3a764000063ffffffff613b7d16565b9063ffffffff613a8516565b600080600084861161379a57613793858763ffffffff61218e16565b60006137ad565b6137aa868663ffffffff61218e16565b60015b91509150806137d5576137d06137c3838661392c565b879063ffffffff61252316565b612d50565b612d506137e2838661392c565b879063ffffffff61218e16565b60006137f9613c00565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7f69737375616e6365526174696f000000000000000000000000000000000000006040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b15801561387557600080fd5b505afa158015613889573d6000803e3d6000fd5b505050506040513d602081101561389f57600080fd5b5051905090565b60006138b0613c00565b6001600160a01b03166323257c2b6d53797374656d53657474696e677360901b7f65787465726e616c546f6b656e51756f746100000000000000000000000000006040518363ffffffff1660e01b8152600401808381526020018281526020019250505060206040518083038186803b15801561387557600080fd5b6000811580613939575082155b612ff957612ff4612fef8484613d53565b60006139646b4c69717569646174696f6e7360a01b613d85565b905090565b60006111c5600a83900a613983858263ffffffff613a8516565b9063ffffffff613b7d16565b60006139646524b9b9bab2b960d11b613d85565b6000806139ae6137ef565b905060006139ba6138a6565b905060006139ce898463ffffffff61218e16565b90506139da818861392c565b9350613a04600089116139ee5760006139fe565b6139fe898563ffffffff61218e16565b8761392c565b9050613a16848263ffffffff61252316565b9350613a28828463ffffffff61218e16565b9050613a34818661392c565b905083811015613a4a5760009350505050610d99565b613a5a818563ffffffff61218e16565b9350613a6c898363ffffffff61218e16565b9050613a788482612fd1565b9998505050505050505050565b6000808211613adb576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b6000828481613ae657fe5b04949350505050565b600080613afa613e6e565b6001600160a01b0316630c71cd23846040518263ffffffff1660e01b815260040180828152602001915050604080518083038186803b158015613b3c57600080fd5b505afa158015613b50573d6000803e3d6000fd5b505050506040513d6040811015613b6657600080fd5b508051602090910151909250905061337a81613e89565b600082613b8c575060006111c8565b82820282848281613b9957fe5b04146111c55760405162461bcd60e51b81526004018080602001828103825260218152602001806140016021913960400191505060405180910390fd5b6000670de0b6b3a7640000613bf1848463ffffffff613b7d16565b81613bf857fe5b049392505050565b60006139647f466c657869626c6553746f726167650000000000000000000000000000000000613d85565b6000811580613c38575082155b612ff957612ff4613c4883613ec6565b613c5185613ec6565b9063ffffffff613edc16565b60006305f5e10082046005600a820610613c7557600a015b600a900492915050565b600554604080516397bb3ce960e01b81526004810184905290516000926001600160a01b0316916397bb3ce9916024808301926020929190829003018186803b158015613ccb57600080fd5b505afa158015613cdf573d6000803e3d6000fd5b505050506040513d6020811015613cf557600080fd5b50516001600160a01b0316141561297b576040805162461bcd60e51b815260206004820152601e60248201527f54617267657420746f6b656e206973206e6f7420726567697374657265640000604482015290519081900360640190fd5b6000811580613d60575082155b612ff957612ff4613d7083613ec6565b613d7985613ec6565b9063ffffffff613ef516565b60008181526003602090815260408083205481517f4d697373696e6720616464726573733a200000000000000000000000000000009381019390935260318084018690528251808503909101815260519093019091526001600160a01b03169081612d365760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613e33578181015183820152602001613e1b565b50505050905090810190601f168015613e605780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b60006139646c45786368616e6765526174657360981b613d85565b801561297b5760405162461bcd60e51b815260040180806020018281038252602b815260200180613fa7602b913960400191505060405180910390fd5b60006111c882633b9aca0063ffffffff613b7d16565b60006111c583836b033b2e3c9fd0803ce8000000613f0e565b60006111c583836b033b2e3c9fd0803ce8000000613f46565b600080613f288461376b87600a870263ffffffff613b7d16565b90506005600a825b0610613f3a57600a015b600a9004949350505050565b600080600a8304613f5d868663ffffffff613b7d16565b81613f6457fe5b0490506005600a82613f3056fe596f75206d757374206265206e6f6d696e61746564206265666f726520796f752063616e20616363657074206f776e657273686970412070796e7468206f7220612065787465726e616c20746f6b656e207261746520697320696e76616c69644f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6e536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774e6f7420656e6f7567682065787465726e616c207374616b656420616d6f756e745472616e7366657272696e67207374616b696e6720746f6b656e20686173206265656e206661696c6564a265627a7a72315820cfbd39bfcc87230b5e9aef41175923b35ce6712d42e1c3176bc6b48a8a8ba80164736f6c63430005100032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001c19d81a6f11958d58130ddbc505933426c80369000000000000000000000000263b671648675bda5263525eca554e4d5697e2100000000000000000000000007015cd1e78ba1428d103b0c2513077b2826b64fc
-----Decoded View---------------
Arg [0] : _owner (address): 0x1c19D81a6F11958D58130DdbC505933426C80369
Arg [1] : _stakingState (address): 0x263b671648675Bda5263525ecA554e4d5697e210
Arg [2] : _resolver (address): 0x7015cd1E78bA1428d103B0C2513077b2826b64fc
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000001c19d81a6f11958d58130ddbc505933426c80369
Arg [1] : 000000000000000000000000263b671648675bda5263525eca554e4d5697e210
Arg [2] : 0000000000000000000000007015cd1e78ba1428d103b0c2513077b2826b64fc
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
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.