Overview
S Balance
0 S
S Value
-More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
1496444 | 8 days ago | Contract Creation | 0 S |
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 Source Code Verified (Exact Match)
Contract Name:
FactoryLib
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "./CommonLib.sol"; import "./VaultTypeLib.sol"; import "../../interfaces/IPlatform.sol"; import "../../interfaces/IStrategy.sol"; import "../../interfaces/ISwapper.sol"; import "../../interfaces/IFactory.sol"; import "../../interfaces/IPriceReader.sol"; import "../../interfaces/IVault.sol"; import "../../interfaces/IRVault.sol"; import "../../interfaces/IVaultProxy.sol"; import "../../interfaces/IStrategyProxy.sol"; library FactoryLib { using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.Bytes32Set; uint public constant BOOST_REWARD_DURATION = 86400 * 30; struct WhatToBuildVars { bytes32[] strategyIdHashes; uint strategyIdHashesLen; IFactory.Farm[] farms; uint farmsLen; string[] vaultTypes; uint vaultTypesLen; // getVaultInitParamsVariants returns string[] vaultType; uint[] usedAddresses; uint[] usedNums; address[] allVaultInitAddresses; uint[] allVaultInitNums; uint allVaultInitAddressesIndex; uint allVaultInitNumsIndex; // strategy initVariants returns string[] strategyVariantDesc; uint strategyVariantDescLen; address[] allStrategyInitAddresses; uint[] allStrategyInitNums; int24[] allStrategyInitTicks; uint allStrategyInitAddressesIndex; uint allStrategyInitNumsIndex; uint allStrategyInitTicksIndex; // target vault init params address[] vaultInitAddresses; uint[] vaultInitNums; // target strategy init params address[] strategyInitAddresses; uint[] strategyInitNums; int24[] strategyInitTicks; uint usedStrategyInitAddresses; uint usedStrategyInitNums; uint usedStrategyInitTicks; // total results, used for counters too uint total; uint totalVaultInitAddresses; uint totalVaultInitNums; uint totalStrategyInitAddresses; uint totalStrategyInitNums; uint totalStrategyInitTicks; // counters and length uint i; uint j; uint c; } struct VaultPostDeployVars { bool isRewardingVaultType; uint minInitialBoostDuration; uint minInitialBoostPerDay; } struct GetVaultInitParamsVariantsVars { string[] vaultTypes; uint total; uint totalVaultInitAddresses; uint totalVaultInitNums; uint len; } function whatToBuild(address platform) external view returns ( string[] memory desc, string[] memory vaultType, string[] memory strategyId, uint[10][] memory initIndexes, address[] memory vaultInitAddresses, uint[] memory vaultInitNums, address[] memory strategyInitAddresses, uint[] memory strategyInitNums, int24[] memory strategyInitTicks ) { WhatToBuildVars memory vars; IFactory factory = IFactory(IPlatform(platform).factory()); vars.strategyIdHashes = factory.strategyLogicIdHashes(); vars.strategyIdHashesLen = vars.strategyIdHashes.length; vars.farms = factory.farms(); vars.farmsLen = vars.farms.length; for (; vars.i < vars.strategyIdHashesLen; ++vars.i) { IFactory.StrategyLogicConfig memory strategyConfig; //slither-disable-next-line unused-return strategyConfig = factory.strategyLogicConfig(vars.strategyIdHashes[vars.i]); if (strategyConfig.deployAllowed) { (vars.vaultType, vars.usedAddresses, vars.usedNums, vars.allVaultInitAddresses, vars.allVaultInitNums) = _getVaultInitParamsVariants(platform, strategyConfig.implementation); // nosemgrep vars.vaultTypesLen = vars.vaultType.length; vars.allVaultInitAddressesIndex = 0; vars.allVaultInitNumsIndex = 0; // nosemgrep for (uint k; k < vars.vaultTypesLen; ++k) { vars.vaultInitAddresses = new address[](vars.usedAddresses[k]); vars.vaultInitNums = new uint[](vars.usedNums[k]); // nosemgrep for (uint j; j < vars.usedAddresses[k]; ++j) { vars.vaultInitAddresses[j] = vars.allVaultInitAddresses[vars.allVaultInitAddressesIndex]; ++vars.allVaultInitAddressesIndex; } // nosemgrep for (uint j; j < vars.usedNums[k]; ++j) { vars.vaultInitNums[j] = vars.allVaultInitNums[vars.allVaultInitNumsIndex]; ++vars.allVaultInitNumsIndex; } ( vars.strategyVariantDesc, vars.allStrategyInitAddresses, vars.allStrategyInitNums, vars.allStrategyInitTicks ) = IStrategy(strategyConfig.implementation).initVariants(platform); vars.allStrategyInitAddressesIndex = 0; vars.allStrategyInitNumsIndex = 0; vars.allStrategyInitTicksIndex = 0; // nosemgrep uint len = vars.strategyVariantDesc.length; for (vars.j = 0; vars.j < len; ++vars.j) { // nosemgrep uint size = vars.allStrategyInitAddresses.length / len; vars.usedStrategyInitAddresses = 0; vars.usedStrategyInitNums = 0; vars.usedStrategyInitTicks = 0; vars.strategyInitAddresses = new address[](size); // nosemgrep for (uint c; c < size; ++c) { vars.strategyInitAddresses[c] = vars.allStrategyInitAddresses[vars.allStrategyInitAddressesIndex]; ++vars.allStrategyInitAddressesIndex; ++vars.usedStrategyInitAddresses; } // nosemgrep size = vars.allStrategyInitNums.length / len; vars.strategyInitNums = new uint[](size); // nosemgrep for (uint c; c < size; ++c) { vars.strategyInitNums[c] = vars.allStrategyInitNums[vars.allStrategyInitNumsIndex]; ++vars.allStrategyInitNumsIndex; ++vars.usedStrategyInitNums; } // nosemgrep size = vars.allStrategyInitTicks.length / len; vars.strategyInitTicks = new int24[](size); // nosemgrep for (uint c; c < size; ++c) { vars.strategyInitTicks[c] = vars.allStrategyInitTicks[vars.allStrategyInitTicksIndex]; ++vars.allStrategyInitTicksIndex; ++vars.usedStrategyInitTicks; } bytes32 _deploymentKey = getDeploymentKey( vars.vaultType[k], strategyConfig.id, vars.vaultInitAddresses, vars.vaultInitNums, vars.strategyInitAddresses, vars.strategyInitNums, vars.strategyInitTicks, [1, 0, 1, 1, 0] ); if (factory.deploymentKey(_deploymentKey) == address(0)) { ++vars.total; vars.totalVaultInitAddresses += vars.usedAddresses[k]; vars.totalVaultInitNums += vars.usedNums[k]; vars.totalStrategyInitAddresses += vars.usedStrategyInitAddresses; vars.totalStrategyInitNums += vars.usedStrategyInitNums; vars.totalStrategyInitTicks += vars.usedStrategyInitTicks; } } } } } desc = new string[](vars.total); vaultType = new string[](vars.total); strategyId = new string[](vars.total); initIndexes = new uint[10][](vars.total); vaultInitAddresses = new address[](vars.totalVaultInitAddresses); vaultInitNums = new uint[](vars.totalVaultInitNums); strategyInitAddresses = new address[](vars.totalStrategyInitAddresses); strategyInitNums = new uint[](vars.totalStrategyInitNums); strategyInitTicks = new int24[](vars.totalStrategyInitTicks); vars.total = 0; vars.totalVaultInitAddresses = 0; vars.totalVaultInitNums = 0; vars.totalStrategyInitAddresses = 0; vars.totalStrategyInitNums = 0; vars.totalStrategyInitTicks = 0; for (vars.i = 0; vars.i < vars.strategyIdHashesLen; ++vars.i) { IFactory.StrategyLogicConfig memory strategyConfig; //slither-disable-next-line unused-return strategyConfig = factory.strategyLogicConfig(vars.strategyIdHashes[vars.i]); if (strategyConfig.deployAllowed) { (vars.vaultType, vars.usedAddresses, vars.usedNums, vars.allVaultInitAddresses, vars.allVaultInitNums) = _getVaultInitParamsVariants(platform, strategyConfig.implementation); // nosemgrep vars.vaultTypesLen = vars.vaultType.length; vars.allVaultInitAddressesIndex = 0; vars.allVaultInitNumsIndex = 0; // nosemgrep for (uint k; k < vars.vaultTypesLen; ++k) { vars.vaultInitAddresses = new address[](vars.usedAddresses[k]); vars.vaultInitNums = new uint[](vars.usedNums[k]); // nosemgrep for (uint j; j < vars.usedAddresses[k]; ++j) { vars.vaultInitAddresses[j] = vars.allVaultInitAddresses[vars.allVaultInitAddressesIndex]; ++vars.allVaultInitAddressesIndex; } // nosemgrep for (uint j; j < vars.usedNums[k]; ++j) { vars.vaultInitNums[j] = vars.allVaultInitNums[vars.allVaultInitNumsIndex]; ++vars.allVaultInitNumsIndex; } ( vars.strategyVariantDesc, vars.allStrategyInitAddresses, vars.allStrategyInitNums, vars.allStrategyInitTicks ) = IStrategy(strategyConfig.implementation).initVariants(platform); vars.allStrategyInitAddressesIndex = 0; vars.allStrategyInitNumsIndex = 0; vars.allStrategyInitTicksIndex = 0; // nosemgrep vars.strategyVariantDescLen = vars.strategyVariantDesc.length; for (vars.j = 0; vars.j < vars.strategyVariantDescLen; ++vars.j) { // nosemgrep uint size = vars.allStrategyInitAddresses.length / vars.strategyVariantDescLen; vars.usedStrategyInitAddresses = 0; vars.usedStrategyInitNums = 0; vars.usedStrategyInitTicks = 0; vars.strategyInitAddresses = new address[](size); // nosemgrep for (uint c; c < size; ++c) { vars.strategyInitAddresses[c] = vars.allStrategyInitAddresses[vars.allStrategyInitAddressesIndex]; ++vars.allStrategyInitAddressesIndex; ++vars.usedStrategyInitAddresses; } // nosemgrep size = vars.allStrategyInitNums.length / vars.strategyVariantDescLen; vars.strategyInitNums = new uint[](size); // nosemgrep for (uint c; c < size; ++c) { vars.strategyInitNums[c] = vars.allStrategyInitNums[vars.allStrategyInitNumsIndex]; ++vars.allStrategyInitNumsIndex; ++vars.usedStrategyInitNums; } // nosemgrep size = vars.allStrategyInitTicks.length / vars.strategyVariantDescLen; vars.strategyInitTicks = new int24[](size); // nosemgrep for (uint c; c < size; ++c) { vars.strategyInitTicks[c] = vars.allStrategyInitTicks[vars.allStrategyInitTicksIndex]; ++vars.allStrategyInitTicksIndex; ++vars.usedStrategyInitTicks; } bytes32 _deploymentKey = getDeploymentKey( vars.vaultType[k], strategyConfig.id, vars.vaultInitAddresses, vars.vaultInitNums, vars.strategyInitAddresses, vars.strategyInitNums, vars.strategyInitTicks, [1, 0, 1, 1, 0] ); if (factory.deploymentKey(_deploymentKey) == address(0)) { desc[vars.total] = vars.strategyVariantDesc[vars.j]; vaultType[vars.total] = vars.vaultType[k]; strategyId[vars.total] = strategyConfig.id; initIndexes[vars.total][0] = vars.totalVaultInitAddresses; initIndexes[vars.total][1] = vars.totalVaultInitAddresses + vars.usedAddresses[k]; initIndexes[vars.total][2] = vars.totalVaultInitNums; initIndexes[vars.total][3] = vars.totalVaultInitNums + vars.usedNums[k]; initIndexes[vars.total][4] = vars.totalStrategyInitAddresses; initIndexes[vars.total][5] = vars.totalStrategyInitAddresses + vars.usedStrategyInitAddresses; initIndexes[vars.total][6] = vars.totalStrategyInitNums; initIndexes[vars.total][7] = vars.totalStrategyInitNums + vars.usedStrategyInitNums; initIndexes[vars.total][8] = vars.totalStrategyInitTicks; initIndexes[vars.total][9] = vars.totalStrategyInitTicks + vars.usedStrategyInitTicks; // nosemgrep for (uint c; c < vars.usedAddresses[k]; ++c) { vaultInitAddresses[vars.totalVaultInitAddresses + c] = vars.vaultInitAddresses[c]; } // nosemgrep for (uint c; c < vars.usedNums[k]; ++c) { vaultInitNums[vars.totalVaultInitNums + c] = vars.vaultInitNums[c]; } // nosemgrep for (uint c; c < vars.usedStrategyInitAddresses; ++c) { strategyInitAddresses[vars.totalStrategyInitAddresses + c] = vars.strategyInitAddresses[c]; } // nosemgrep for (uint c; c < vars.usedStrategyInitNums; ++c) { strategyInitNums[vars.totalStrategyInitNums + c] = vars.strategyInitNums[c]; } // nosemgrep for (uint c; c < vars.usedStrategyInitTicks; ++c) { strategyInitTicks[vars.totalStrategyInitTicks + c] = vars.strategyInitTicks[c]; } ++vars.total; vars.totalVaultInitAddresses += vars.usedAddresses[k]; vars.totalVaultInitNums += vars.usedNums[k]; vars.totalStrategyInitAddresses += vars.usedStrategyInitAddresses; vars.totalStrategyInitNums += vars.usedStrategyInitNums; vars.totalStrategyInitTicks += vars.usedStrategyInitTicks; } } } } } } function _getVaultInitParamsVariants( address platform, address strategyImplementation ) internal view returns ( string[] memory vaultType, uint[] memory usedAddresses, uint[] memory usedNums, address[] memory allVaultInitAddresses, uint[] memory allVaultInitNums ) { GetVaultInitParamsVariantsVars memory vars; vars.vaultTypes = IStrategy(strategyImplementation).supportedVaultTypes(); vars.len = vars.vaultTypes.length; //slither-disable-next-line unused-return (address[] memory allowedBBTokens,) = IPlatform(platform).allowedBBTokenVaultsFiltered(); uint allowedBBTokensLen = allowedBBTokens.length; // nosemgrep for (uint i; i < vars.len; ++i) { if (CommonLib.eq(vars.vaultTypes[i], VaultTypeLib.COMPOUNDING)) { ++vars.total; } else if ( CommonLib.eq(vars.vaultTypes[i], VaultTypeLib.REWARDING) || CommonLib.eq(vars.vaultTypes[i], VaultTypeLib.REWARDING_MANAGED) ) { vars.total += allowedBBTokensLen; vars.totalVaultInitAddresses += allowedBBTokensLen; } } vaultType = new string[](vars.total); usedAddresses = new uint[](vars.total); usedNums = new uint[](vars.total); allVaultInitAddresses = new address[](vars.totalVaultInitAddresses); allVaultInitNums = new uint[](vars.totalVaultInitNums); // now its always 0, but function can be upgraded without changing interface // vaultType index, allVaultInitAddresses index, allVaultInitNums index uint[3] memory indexes; // nosemgrep for (uint i; i < vars.len; ++i) { if (CommonLib.eq(vars.vaultTypes[i], VaultTypeLib.COMPOUNDING)) { vaultType[indexes[0]] = vars.vaultTypes[i]; ++indexes[0]; } else if ( CommonLib.eq(vars.vaultTypes[i], VaultTypeLib.REWARDING) || CommonLib.eq(vars.vaultTypes[i], VaultTypeLib.REWARDING_MANAGED) ) { // nosemgrep for (uint k; k < allowedBBTokensLen; ++k) { vaultType[indexes[0]] = vars.vaultTypes[i]; allVaultInitAddresses[indexes[1]] = allowedBBTokens[k]; usedAddresses[indexes[0]] = 1; ++indexes[0]; ++indexes[1]; } } } } function getExchangeAssetIndex( address platform, address[] memory assets ) external view returns (uint exchangeAssetIndex) { address targetExchangeAsset = IPlatform(platform).targetExchangeAsset(); uint len = assets.length; // nosemgrep for (uint i; i < len; ++i) { if (assets[i] == targetExchangeAsset) { return i; } } exchangeAssetIndex = type(uint).max; uint minRoutes = type(uint).max; ISwapper swapper = ISwapper(IPlatform(platform).swapper()); // nosemgrep for (uint i; i < len; ++i) { //slither-disable-next-line unused-return (ISwapper.PoolData[] memory route,) = swapper.buildRoute(assets[i], targetExchangeAsset); // nosemgrep uint routeLength = route.length; if (routeLength < minRoutes) { minRoutes = routeLength; exchangeAssetIndex = i; } } if (exchangeAssetIndex == type(uint).max) { revert ISwapper.NoRouteFound(); } if (exchangeAssetIndex > type(uint).max) revert ISwapper.NoRoutesForAssets(); } function getName( string memory vaultType, string memory id, string memory symbols, string memory specificName, address[] memory vaultInitAddresses ) public view returns (string memory name) { name = string.concat("Stability ", symbols, " ", id); if (keccak256(bytes(specificName)) != keccak256(bytes(""))) { name = string.concat(name, " ", specificName); } if (keccak256(bytes(vaultType)) == keccak256(bytes(VaultTypeLib.REWARDING))) { name = string.concat(name, " ", IERC20Metadata(vaultInitAddresses[0]).symbol(), " reward"); } } function getDeploymentKey( string memory vaultType, string memory strategyId, address[] memory initVaultAddresses, uint[] memory initVaultNums, address[] memory initStrategyAddresses, uint[] memory initStrategyNums, int24[] memory initStrategyTicks, uint8[5] memory usedValuesForKey ) public pure returns (bytes32) { uint key = uint(keccak256(abi.encodePacked(vaultType))); unchecked { key += uint(keccak256(abi.encodePacked(strategyId))); } uint i; uint len; // process initVaultAddresses len = initVaultAddresses.length; if (len > usedValuesForKey[0]) { len = usedValuesForKey[0]; } for (; i < len; ++i) { unchecked { key += uint(uint160(initVaultAddresses[i])); } } // process initVaultNums len = initVaultNums.length; if (len > usedValuesForKey[1]) { len = usedValuesForKey[1]; } for (i = 0; i < len; ++i) { unchecked { key += initVaultNums[i]; } } // process initStrategyAddresses len = initStrategyAddresses.length; if (len > usedValuesForKey[2]) { len = usedValuesForKey[2]; } for (i = 0; i < len; ++i) { unchecked { key += uint(uint160(initStrategyAddresses[i])); } } // process initStrategyNums len = initStrategyNums.length; if (len > usedValuesForKey[3]) { len = usedValuesForKey[3]; } for (i = 0; i < len; ++i) { unchecked { key += initStrategyNums[i]; } } // process initStrategyTicks len = initStrategyTicks.length; if (len > usedValuesForKey[4]) { len = usedValuesForKey[4]; } for (i = 0; i < len; ++i) { unchecked { key += initStrategyTicks[i] >= 0 ? uint(int(initStrategyTicks[i])) : uint(-int(initStrategyTicks[i])); } } return bytes32(key); } function vaultPostDeploy( address platform, address vault, string memory vaultType, address[] memory vaultInitAddresses, uint[] memory vaultInitNums ) external { VaultPostDeployVars memory vars; vars.isRewardingVaultType = CommonLib.eq(vaultType, VaultTypeLib.REWARDING); if (vars.isRewardingVaultType || CommonLib.eq(vaultType, VaultTypeLib.REWARDING_MANAGED)) { IPlatform(platform).useAllowedBBTokenVault(vaultInitAddresses[0]); IPriceReader priceReader = IPriceReader(IPlatform(platform).priceReader()); vars.minInitialBoostDuration = IPlatform(platform).minInitialBoostDuration(); vars.minInitialBoostPerDay = IPlatform(platform).minInitialBoostPerDay(); vaultInitAddresses = IRVault(vault).rewardTokens(); uint boostTokensLen = vaultInitAddresses.length - 1; uint totalInitialBoostUsdPerDay; // nosemgrep for (uint i; i < boostTokensLen; ++i) { address token = vaultInitAddresses[1 + i]; uint durationSeconds = vars.isRewardingVaultType ? BOOST_REWARD_DURATION : vaultInitNums[1 + i]; if (durationSeconds < vars.minInitialBoostDuration) { revert IFactory.BoostDurationTooLow(); } uint initialNotifyAmount = vars.isRewardingVaultType ? vaultInitNums[i] : vaultInitNums[1 + boostTokensLen + i]; //slither-disable-next-line unused-return (uint price,) = priceReader.getPrice(token); totalInitialBoostUsdPerDay += ( ((((initialNotifyAmount * 1e18) / 10 ** IERC20Metadata(token).decimals()) * price) / 1e18) * 86400 ) / durationSeconds; if (initialNotifyAmount > 0) { IERC20(token).safeTransferFrom(msg.sender, address(this), initialNotifyAmount); IERC20(token).forceApprove(vault, initialNotifyAmount); IRVault(vault).notifyTargetRewardAmount(1 + i, initialNotifyAmount); } } if (totalInitialBoostUsdPerDay == 0) { revert IFactory.BoostAmountIsZero(); } if (totalInitialBoostUsdPerDay < vars.minInitialBoostPerDay) { revert IFactory.BoostAmountTooLow(); } } } function setVaultConfig( IFactory.FactoryStorage storage $, IFactory.VaultConfig memory vaultConfig_ ) external returns (bool needGovOrMultisigAccess) { string memory type_ = vaultConfig_.vaultType; bytes32 typeHash = keccak256(abi.encodePacked(type_)); $.vaultConfig[typeHash] = vaultConfig_; bool newVaultType = $.vaultTypeHashes.add(typeHash); if (!newVaultType) { needGovOrMultisigAccess = true; } emit IFactory.VaultConfigChanged( type_, vaultConfig_.implementation, vaultConfig_.deployAllowed, vaultConfig_.upgradeAllowed, newVaultType ); } function upgradeVaultProxy(IFactory.FactoryStorage storage $, address vault) external { IVaultProxy proxy = IVaultProxy(vault); bytes32 vaultTypeHash = proxy.vaultTypeHash(); address oldImplementation = proxy.implementation(); IFactory.VaultConfig memory tempVaultConfig = $.vaultConfig[vaultTypeHash]; address newImplementation = tempVaultConfig.implementation; if (!tempVaultConfig.upgradeAllowed) { revert IFactory.UpgradeDenied(vaultTypeHash); } if (oldImplementation == newImplementation) { revert IFactory.AlreadyLastVersion(vaultTypeHash); } proxy.upgrade(); emit IFactory.VaultProxyUpgraded(vault, oldImplementation, newImplementation); } function upgradeStrategyProxy(IFactory.FactoryStorage storage $, address strategyProxy) external { IStrategyProxy proxy = IStrategyProxy(strategyProxy); bytes32 idHash = proxy.strategyImplementationLogicIdHash(); IFactory.StrategyLogicConfig storage config = $.strategyLogicConfig[idHash]; address oldImplementation = proxy.implementation(); address newImplementation = config.implementation; if (!config.upgradeAllowed) { revert IFactory.UpgradeDenied(idHash); } if (oldImplementation == newImplementation) { revert IFactory.AlreadyLastVersion(idHash); } proxy.upgrade(); emit IFactory.StrategyProxyUpgraded(strategyProxy, oldImplementation, newImplementation); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "./ConstantsLib.sol"; library CommonLib { function filterAddresses( address[] memory addresses, address addressToRemove ) external pure returns (address[] memory filteredAddresses) { uint len = addresses.length; uint newLen; // nosemgrep for (uint i; i < len; ++i) { if (addresses[i] != addressToRemove) { ++newLen; } } filteredAddresses = new address[](newLen); uint k; // nosemgrep for (uint i; i < len; ++i) { if (addresses[i] != addressToRemove) { filteredAddresses[k] = addresses[i]; ++k; } } } function formatUsdAmount(uint amount) external pure returns (string memory formattedPrice) { uint dollars = amount / 10 ** 18; string memory priceStr; if (dollars >= 1000) { uint kDollars = dollars / 1000; uint kDollarsFraction = (dollars - kDollars * 1000) / 10; string memory delimiter = "."; if (kDollarsFraction < 10) { delimiter = ".0"; } priceStr = string.concat(Strings.toString(kDollars), delimiter, Strings.toString(kDollarsFraction), "k"); } else if (dollars >= 100) { priceStr = Strings.toString(dollars); } else { uint dollarsFraction = (amount - dollars * 10 ** 18) / 10 ** 14; if (dollarsFraction > 0) { string memory dollarsFractionDelimiter = "."; if (dollarsFraction < 10) { dollarsFractionDelimiter = ".000"; } else if (dollarsFraction < 100) { dollarsFractionDelimiter = ".00"; } else if (dollarsFraction < 1000) { dollarsFractionDelimiter = ".0"; } priceStr = string.concat( Strings.toString(dollars), dollarsFractionDelimiter, Strings.toString(dollarsFraction) ); } else { priceStr = Strings.toString(dollars); } } formattedPrice = string.concat("$", priceStr); } function formatApr(uint apr) external pure returns (string memory formattedApr) { uint aprInt = apr * 100 / ConstantsLib.DENOMINATOR; uint aprFraction = (apr - aprInt * ConstantsLib.DENOMINATOR / 100) / 10; string memory delimiter = "."; if (aprFraction < 10) { delimiter = ".0"; } formattedApr = string.concat(Strings.toString(aprInt), delimiter, Strings.toString(aprFraction), "%"); } function implodeSymbols( address[] memory assets, string memory delimiter ) external view returns (string memory outString) { return implode(getSymbols(assets), delimiter); } function implode(string[] memory strings, string memory delimiter) public pure returns (string memory outString) { uint len = strings.length; if (len == 0) { return ""; } outString = strings[0]; // nosemgrep for (uint i = 1; i < len; ++i) { outString = string.concat(outString, delimiter, strings[i]); } return outString; } function getSymbols(address[] memory assets) public view returns (string[] memory symbols) { uint len = assets.length; symbols = new string[](len); // nosemgrep for (uint i; i < len; ++i) { symbols[i] = IERC20Metadata(assets[i]).symbol(); } } function bytesToBytes32(bytes memory b) external pure returns (bytes32 out) { // nosemgrep for (uint i; i < b.length; ++i) { out |= bytes32(b[i] & 0xFF) >> (i * 8); } // return out; } function bToHex(bytes memory buffer) external pure returns (string memory) { // Fixed buffer size for hexadecimal convertion bytes memory converted = new bytes(buffer.length * 2); bytes memory _base = "0123456789abcdef"; uint baseLength = _base.length; // nosemgrep for (uint i; i < buffer.length; ++i) { converted[i * 2] = _base[uint8(buffer[i]) / baseLength]; converted[i * 2 + 1] = _base[uint8(buffer[i]) % baseLength]; } return string(abi.encodePacked(converted)); } function shortId(string memory id) external pure returns (string memory) { uint words = 1; bytes memory idBytes = bytes(id); uint idBytesLength = idBytes.length; // nosemgrep for (uint i; i < idBytesLength; ++i) { if (keccak256(bytes(abi.encodePacked(idBytes[i]))) == keccak256(bytes(" "))) { ++words; } } bytes memory _shortId = new bytes(words); uint k = 1; _shortId[0] = idBytes[0]; // nosemgrep for (uint i = 1; i < idBytesLength; ++i) { if (keccak256(bytes(abi.encodePacked(idBytes[i]))) == keccak256(bytes(" "))) { if (keccak256(bytes(abi.encodePacked(idBytes[i + 1]))) == keccak256(bytes("0"))) { _shortId[k] = idBytes[i + 3]; } else { _shortId[k] = idBytes[i + 1]; } ++k; } } return string(abi.encodePacked(_shortId)); } function eq(string memory a, string memory b) external pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } function u2s(uint num) external pure returns (string memory) { return Strings.toString(num); } function i2s(int num) external pure returns (string memory) { return Strings.toString(num > 0 ? uint(num) : uint(-num)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; library VaultTypeLib { string internal constant COMPOUNDING = "Compounding"; string internal constant REWARDING = "Rewarding"; string internal constant REWARDING_MANAGED = "Rewarding Managed"; string internal constant SPLITTER_MANAGED = "Splitter Managed"; string internal constant SPLITTER_AUTO = "Splitter Automatic"; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; /// @notice Interface of the main contract and entry point to the platform. /// @author Alien Deployer (https://github.com/a17) /// @author Jude (https://github.com/iammrjude) /// @author JodsMigel (https://github.com/JodsMigel) interface IPlatform { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error AlreadyAnnounced(); error SameVersion(); error NoNewVersion(); error UpgradeTimerIsNotOver(uint TimerTimestamp); error IncorrectFee(uint minFee, uint maxFee); error NotEnoughAllowedBBToken(); error TokenAlreadyExistsInSet(address token); error AggregatorNotExists(address dexAggRouter); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ event PlatformVersion(string version); event UpgradeAnnounce( string oldVersion, string newVersion, address[] proxies, address[] newImplementations, uint timelock ); event CancelUpgrade(string oldVersion, string newVersion); event ProxyUpgraded( address indexed proxy, address implementation, string oldContractVersion, string newContractVersion ); event Addresses( address multisig_, address factory_, address priceReader_, address swapper_, address buildingPermitToken_, address vaultManager_, address strategyLogic_, address aprOracle_, address hardWorker, address rebalancer, address zap, address bridge ); event OperatorAdded(address operator); event OperatorRemoved(address operator); event FeesChanged(uint fee, uint feeShareVaultManager, uint feeShareStrategyLogic, uint feeShareEcosystem); event MinInitialBoostChanged(uint minInitialBoostPerDay, uint minInitialBoostDuration); event NewAmmAdapter(string id, address proxy); event EcosystemRevenueReceiver(address receiver); event SetAllowedBBTokenVaults(address bbToken, uint vaultsToBuild, bool firstSet); event RemoveAllowedBBToken(address bbToken); event AddAllowedBoostRewardToken(address token); event RemoveAllowedBoostRewardToken(address token); event AddDefaultBoostRewardToken(address token); event RemoveDefaultBoostRewardToken(address token); event AddBoostTokens(address[] allowedBoostRewardToken, address[] defaultBoostRewardToken); event AllowedBBTokenVaultUsed(address bbToken, uint vaultToUse); event AddDexAggregator(address router); event RemoveDexAggregator(address router); event MinTvlForFreeHardWorkChanged(uint oldValue, uint newValue); event CustomVaultFee(address vault, uint platformFee); event Rebalancer(address rebalancer_); event Bridge(address bridge_); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DATA TYPES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ struct PlatformUpgrade { string newVersion; address[] proxies; address[] newImplementations; } struct PlatformSettings { string networkName; bytes32 networkExtra; uint fee; uint feeShareVaultManager; uint feeShareStrategyLogic; uint feeShareEcosystem; uint minInitialBoostPerDay; uint minInitialBoostDuration; } struct AmmAdapter { string id; address proxy; } struct SetupAddresses { address factory; address priceReader; address swapper; address buildingPermitToken; address buildingPayPerVaultToken; address vaultManager; address strategyLogic; address aprOracle; address targetExchangeAsset; address hardWorker; address zap; address bridge; address rebalancer; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* VIEW FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Platform version in CalVer scheme: YY.MM.MINOR-tag. Updates on core contract upgrades. function platformVersion() external view returns (string memory); /// @notice Time delay for proxy upgrades of core contracts and changing important platform settings by multisig //slither-disable-next-line naming-convention function TIME_LOCK() external view returns (uint); /// @notice DAO governance function governance() external view returns (address); /// @notice Core team multi signature wallet. Development and operations fund function multisig() external view returns (address); /// @notice This NFT allow user to build limited number of vaults per week function buildingPermitToken() external view returns (address); /// @notice This ERC20 token is used as payment token for vault building function buildingPayPerVaultToken() external view returns (address); /// @notice Receiver of ecosystem revenue function ecosystemRevenueReceiver() external view returns (address); /// @dev The best asset in a network for swaps between strategy assets and farms rewards assets /// The target exchange asset is used for finding the best strategy's exchange asset. /// Rhe fewer routes needed to swap to the target exchange asset, the better. function targetExchangeAsset() external view returns (address); /// @notice Platform factory assembling vaults. Stores settings, strategy logic, farms. /// Provides the opportunity to upgrade vaults and strategies. /// @return Address of Factory proxy function factory() external view returns (address); /// @notice The holders of these NFT receive a share of the vault revenue /// @return Address of VaultManager proxy function vaultManager() external view returns (address); /// @notice The holders of these tokens receive a share of the revenue received in all vaults using this strategy logic. function strategyLogic() external view returns (address); /// @notice Combining oracle and DeX spot prices /// @return Address of PriceReader proxy function priceReader() external view returns (address); /// @notice Providing underlying assets APRs on-chain /// @return Address of AprOracle proxy function aprOracle() external view returns (address); /// @notice On-chain price quoter and swapper /// @return Address of Swapper proxy function swapper() external view returns (address); /// @notice HardWork resolver and caller /// @return Address of HardWorker proxy function hardWorker() external view returns (address); /// @notice Rebalance resolver /// @return Address of Rebalancer proxy function rebalancer() external view returns (address); /// @notice ZAP feature /// @return Address of Zap proxy function zap() external view returns (address); /// @notice Stability Bridge /// @return Address of Bridge proxy function bridge() external view returns (address); /// @notice Name of current EVM network function networkName() external view returns (string memory); /// @notice Minimal initial boost rewards per day USD amount which needs to create rewarding vault function minInitialBoostPerDay() external view returns (uint); /// @notice Minimal boost rewards vesting duration for initial boost function minInitialBoostDuration() external view returns (uint); /// @notice This function provides the timestamp of the platform upgrade timelock. /// @dev This function is an external view function, meaning it doesn't modify the state. /// @return uint representing the timestamp of the platform upgrade timelock. function platformUpgradeTimelock() external view returns (uint); /// @dev Extra network data /// @return 0-2 bytes - color /// 3-5 bytes - background color /// 6-31 bytes - free function networkExtra() external view returns (bytes32); /// @notice Pending platform upgrade data function pendingPlatformUpgrade() external view returns (PlatformUpgrade memory); /// @notice Get platform revenue fee settings /// @return fee Revenue fee % (between MIN_FEE - MAX_FEE) with DENOMINATOR precision. /// @return feeShareVaultManager Revenue fee share % of VaultManager tokenId owner /// @return feeShareStrategyLogic Revenue fee share % of StrategyLogic tokenId owner /// @return feeShareEcosystem Revenue fee share % of ecosystemFeeReceiver function getFees() external view returns (uint fee, uint feeShareVaultManager, uint feeShareStrategyLogic, uint feeShareEcosystem); /// @notice Get custom vault platform fee /// @return fee revenue fee % with DENOMINATOR precision function getCustomVaultFee(address vault) external view returns (uint fee); /// @notice Platform settings function getPlatformSettings() external view returns (PlatformSettings memory); /// @notice AMM adapters of the platform function getAmmAdapters() external view returns (string[] memory id, address[] memory proxy); /// @notice Get AMM adapter data by hash /// @param ammAdapterIdHash Keccak256 hash of adapter ID string /// @return ID string and proxy address of AMM adapter function ammAdapter(bytes32 ammAdapterIdHash) external view returns (AmmAdapter memory); /// @notice Allowed buy-back tokens for rewarding vaults function allowedBBTokens() external view returns (address[] memory); /// @notice Vaults building limit for buy-back token. /// This limit decrements when a vault for BB-token is built. /// @param token Allowed buy-back token /// @return vaultsLimit Number of vaults that can be built for BB-token function allowedBBTokenVaults(address token) external view returns (uint vaultsLimit); /// @notice Vaults building limits for allowed buy-back tokens. /// @return bbToken Allowed buy-back tokens /// @return vaultsLimit Number of vaults that can be built for BB-tokens function allowedBBTokenVaults() external view returns (address[] memory bbToken, uint[] memory vaultsLimit); /// @notice Non-zero vaults building limits for allowed buy-back tokens. /// @return bbToken Allowed buy-back tokens /// @return vaultsLimit Number of vaults that can be built for BB-tokens function allowedBBTokenVaultsFiltered() external view returns (address[] memory bbToken, uint[] memory vaultsLimit); /// @notice Check address for existance in operators list /// @param operator Address /// @return True if this address is Stability Operator function isOperator(address operator) external view returns (bool); /// @notice Tokens that can be used for boost rewards of rewarding vaults /// @return Addresses of tokens function allowedBoostRewardTokens() external view returns (address[] memory); /// @notice Allowed boost reward tokens that used for unmanaged rewarding vaults creation /// @return Addresses of tokens function defaultBoostRewardTokens() external view returns (address[] memory); /// @notice Allowed boost reward tokens that used for unmanaged rewarding vaults creation /// @param addressToRemove This address will be removed from default boost reward tokens /// @return Addresses of tokens function defaultBoostRewardTokensFiltered(address addressToRemove) external view returns (address[] memory); /// @notice Allowed DeX aggregators /// @return Addresses of DeX aggregator rounters function dexAggregators() external view returns (address[] memory); /// @notice DeX aggregator router address is allowed to be used in the platform /// @param dexAggRouter Address of DeX aggreagator router /// @return Can be used function isAllowedDexAggregatorRouter(address dexAggRouter) external view returns (bool); /// @notice Show minimum TVL for compensate if vault has not enough ETH /// @return Minimum TVL for compensate. function minTvlForFreeHardWork() external view returns (uint); /// @notice Front-end platform viewer /// @return platformAddresses Platform core addresses /// platformAddresses[0] factory /// platformAddresses[1] vaultManager /// platformAddresses[2] strategyLogic /// platformAddresses[3] buildingPermitToken /// platformAddresses[4] buildingPayPerVaultToken /// platformAddresses[5] governance /// platformAddresses[6] multisig /// platformAddresses[7] zap /// platformAddresses[8] bridge /// @return bcAssets Blue chip token addresses /// @return dexAggregators_ DeX aggregators allowed to be used entire the platform /// @return vaultType Vault type ID strings /// @return vaultExtra Vault color, background color and other extra data. Index of vault same as in previous array. /// @return vaultBulldingPrice Price of creating new vault in buildingPayPerVaultToken. Index of vault same as in previous array. /// @return strategyId Strategy logic ID strings /// @return isFarmingStrategy True if strategy is farming strategy. Index of strategy same as in previous array. /// @return strategyTokenURI StrategyLogic NFT tokenId metadata and on-chain image. Index of strategy same as in previous array. /// @return strategyExtra Strategy color, background color and other extra data. Index of strategy same as in previous array. function getData() external view returns ( address[] memory platformAddresses, address[] memory bcAssets, address[] memory dexAggregators_, string[] memory vaultType, bytes32[] memory vaultExtra, uint[] memory vaultBulldingPrice, string[] memory strategyId, bool[] memory isFarmingStrategy, string[] memory strategyTokenURI, bytes32[] memory strategyExtra ); // todo add vaultSymbol, vaultName /// @notice Front-end balances, prices and vault list viewer /// @param yourAccount Address of account to query balances /// @return token Tokens supported by the platform /// @return tokenPrice USD price of token. Index of token same as in previous array. /// @return tokenUserBalance User balance of token. Index of token same as in previous array. /// @return vault Deployed vaults /// @return vaultSharePrice Price 1.0 vault share. Index of vault same as in previous array. /// @return vaultUserBalance User balance of vault. Index of vault same as in previous array. /// @return nft Ecosystem NFTs /// nft[0] BuildingPermitToken /// nft[1] VaultManager /// nft[2] StrategyLogic /// @return nftUserBalance User balance of NFT. Index of NFT same as in previous array. /// @return buildingPayPerVaultTokenBalance User balance of vault creation paying token function getBalance(address yourAccount) external view returns ( address[] memory token, uint[] memory tokenPrice, uint[] memory tokenUserBalance, address[] memory vault, uint[] memory vaultSharePrice, uint[] memory vaultUserBalance, address[] memory nft, uint[] memory nftUserBalance, uint buildingPayPerVaultTokenBalance ); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* WRITE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Add platform operator. /// Only governance and multisig can add operator. /// @param operator Address of new operator function addOperator(address operator) external; /// @notice Remove platform operator. /// Only governance and multisig can remove operator. /// @param operator Address of operator to remove function removeOperator(address operator) external; /// @notice Announce upgrade of platform proxies implementations /// Only governance and multisig can announce platform upgrades. /// @param newVersion New platform version. Version must be changed when upgrading. /// @param proxies Addresses of core contract proxies /// @param newImplementations New implementation for proxy. Index of proxy same as in previous array. function announcePlatformUpgrade( string memory newVersion, address[] memory proxies, address[] memory newImplementations ) external; /// @notice Upgrade platform /// Only operator (multisig is operator too) can ececute pending platform upgrade function upgrade() external; /// @notice Cancel pending platform upgrade /// Only operator (multisig is operator too) can ececute pending platform upgrade function cancelUpgrade() external; /// @notice Register AMM adapter in platform /// @param id AMM adapter ID string from AmmAdapterIdLib /// @param proxy Address of AMM adapter proxy function addAmmAdapter(string memory id, address proxy) external; // todo Only governance and multisig can set allowed bb-token vaults building limit /// @notice Set new vaults building limit for buy-back token /// @param bbToken Address of allowed buy-back token /// @param vaultsToBuild Number of vaults that can be built for BB-token function setAllowedBBTokenVaults(address bbToken, uint vaultsToBuild) external; // todo Only governance and multisig can add allowed boost reward token /// @notice Add new allowed boost reward token /// @param token Address of token function addAllowedBoostRewardToken(address token) external; // todo Only governance and multisig can remove allowed boost reward token /// @notice Remove allowed boost reward token /// @param token Address of allowed boost reward token function removeAllowedBoostRewardToken(address token) external; // todo Only governance and multisig can add default boost reward token /// @notice Add default boost reward token /// @param token Address of default boost reward token function addDefaultBoostRewardToken(address token) external; // todo Only governance and multisig can remove default boost reward token /// @notice Remove default boost reward token /// @param token Address of allowed boost reward token function removeDefaultBoostRewardToken(address token) external; // todo Only governance and multisig can add allowed boost reward token // todo Only governance and multisig can add default boost reward token /// @notice Add new allowed boost reward token /// @notice Add default boost reward token /// @param allowedBoostRewardToken Address of allowed boost reward token /// @param defaultBoostRewardToken Address of default boost reward token function addBoostTokens( address[] memory allowedBoostRewardToken, address[] memory defaultBoostRewardToken ) external; /// @notice Decrease allowed BB-token vault building limit when vault is built /// Only Factory can do it. /// @param bbToken Address of allowed buy-back token function useAllowedBBTokenVault(address bbToken) external; /// @notice Allow DeX aggregator routers to be used in the platform /// @param dexAggRouter Addresses of DeX aggreagator routers function addDexAggregators(address[] memory dexAggRouter) external; /// @notice Remove allowed DeX aggregator router from the platform /// @param dexAggRouter Address of DeX aggreagator router function removeDexAggregator(address dexAggRouter) external; /// @notice Change initial boost rewards settings /// @param minInitialBoostPerDay_ Minimal initial boost rewards per day USD amount which needs to create rewarding vault /// @param minInitialBoostDuration_ Minimal boost rewards vesting duration for initial boost function setInitialBoost(uint minInitialBoostPerDay_, uint minInitialBoostDuration_) external; /// @notice Update new minimum TVL for compensate. /// @param value New minimum TVL for compensate. function setMinTvlForFreeHardWork(uint value) external; /// @notice Set custom platform fee for vault /// @param vault Vault address /// @param platformFee Custom platform fee function setCustomVaultFee(address vault, uint platformFee) external; /// @notice Setup Rebalancer. /// Only Goverannce or Multisig can do this when Rebalancer is not set. /// @param rebalancer_ Proxy address of Bridge function setupRebalancer(address rebalancer_) external; /// @notice Setup Bridge. /// Only Goverannce or Multisig can do this when Bridge is not set. /// @param bridge_ Proxy address of Bridge function setupBridge(address bridge_) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /// @dev Core interface of strategy logic interface IStrategy is IERC165 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ event HardWork( uint apr, uint compoundApr, uint earned, uint tvl, uint duration, uint sharePrice, uint[] assetPrices ); event ExtractFees( uint vaultManagerReceiverFee, uint strategyLogicReceiverFee, uint ecosystemRevenueReceiverFee, uint multisigReceiverFee ); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error NotReadyForHardWork(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DATA TYPES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @custom:storage-location erc7201:stability.StrategyBase struct StrategyBaseStorage { /// @inheritdoc IStrategy address vault; /// @inheritdoc IStrategy uint total; /// @inheritdoc IStrategy uint lastHardWork; /// @inheritdoc IStrategy uint lastApr; /// @inheritdoc IStrategy uint lastAprCompound; /// @inheritdoc IStrategy address[] _assets; /// @inheritdoc IStrategy address _underlying; string _id; uint _exchangeAssetIndex; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* VIEW FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Strategy logic string ID function strategyLogicId() external view returns (string memory); /// @dev Extra data /// @return 0-2 bytes - strategy color /// 3-5 bytes - strategy background color /// 6-31 bytes - free function extra() external view returns (bytes32); /// @dev Types of vault that supported by strategy implementation /// @return types Vault type ID strings function supportedVaultTypes() external view returns (string[] memory types); /// @dev Linked vault address function vault() external view returns (address); /// @dev Final assets that strategy invests function assets() external view returns (address[] memory); /// @notice Final assets and amounts that strategy manages function assetsAmounts() external view returns (address[] memory assets_, uint[] memory amounts_); /// @notice Priced invested assets proportions /// @return proportions Proportions of assets with 18 decimals. Min is 0, max is 1e18. function getAssetsProportions() external view returns (uint[] memory proportions); /// @notice Underlying token address /// @dev Can be used for liquidity farming strategies where AMM has fungible liquidity token (Solidly forks, etc), /// for concentrated liquidity tokenized vaults (Gamma, G-UNI etc) and for other needs. /// @return Address of underlying token or zero address if no underlying in strategy function underlying() external view returns (address); /// @dev Balance of liquidity token or liquidity value function total() external view returns (uint); /// @dev Last HardWork time /// @return Timestamp function lastHardWork() external view returns (uint); /// @dev Last APR of earned USD amount registered by HardWork /// ONLY FOR OFF-CHAIN USE. /// Not trusted asset price can be manipulated. /// @return APR with 18 decimals. 1e18 - 100%. function lastApr() external view returns (uint); /// @dev Last APR of compounded assets registered by HardWork. /// Can be used on-chain. /// @return APR with 18 decimals. 1e18 - 100%. function lastAprCompound() external view returns (uint); /// @notice Calculation of consumed amounts and liquidity/underlying value for provided strategy assets and amounts. /// @param assets_ Strategy assets or part of them, if necessary /// @param amountsMax Amounts of specified assets available for investing /// @return amountsConsumed Cosumed amounts of assets when investing /// @return value Liquidity value or underlying token amount minted when investing function previewDepositAssets( address[] memory assets_, uint[] memory amountsMax ) external view returns (uint[] memory amountsConsumed, uint value); /// @notice Write version of previewDepositAssets /// @param assets_ Strategy assets or part of them, if necessary /// @param amountsMax Amounts of specified assets available for investing /// @return amountsConsumed Cosumed amounts of assets when investing /// @return value Liquidity value or underlying token amount minted when investing function previewDepositAssetsWrite( address[] memory assets_, uint[] memory amountsMax ) external returns (uint[] memory amountsConsumed, uint value); /// @notice All strategy revenue (pool fees, farm rewards etc) that not claimed by strategy yet /// @return assets_ Revenue assets /// @return amounts Amounts. Index of asset same as in previous array. function getRevenue() external view returns (address[] memory assets_, uint[] memory amounts); /// @notice Optional specific name of investing strategy, underyling type, setup variation etc /// @return name Empty string or specific name /// @return showInVaultSymbol Show specific in linked vault symbol function getSpecificName() external view returns (string memory name, bool showInVaultSymbol); /// @notice Variants pf strategy initializations with description of money making mechanic. /// As example, if strategy need farm, then number of variations is number of available farms. /// If CAMM strategy have set of available widths (tick ranges), then number of variations is number of available farms. /// If both example conditions are met then total number or variations = total farms * total widths. /// @param platform_ Need this param because method called when strategy implementation is not initialized /// @return variants Descriptions of the strategy for making money /// @return addresses Init strategy addresses. Indexes for each variants depends of copmpared arrays lengths. /// @return nums Init strategy numbers. Indexes for each variants depends of copmpared arrays lengths. /// @return ticks Init strategy ticks. Indexes for each variants depends of copmpared arrays lengths. function initVariants(address platform_) external view returns (string[] memory variants, address[] memory addresses, uint[] memory nums, int24[] memory ticks); /// @notice How does the strategy make money? /// @return Description in free form function description() external view returns (string memory); /// @notice Is HardWork on vault deposits can be enabled function isHardWorkOnDepositAllowed() external view returns (bool); /// @notice Is HardWork can be executed function isReadyForHardWork() external view returns (bool); /// @notice Strategy not need to process revenue on HardWorks function autoCompoundingByUnderlyingProtocol() external view returns (bool); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* WRITE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev A single universal initializer for all strategy implementations. /// @param addresses All addresses that strategy requires for initialization. Min array length is 2. /// addresses[0]: platform (required) /// addresses[1]: vault (required) /// addresses[2]: initStrategyAddresses[0] (optional) /// addresses[3]: initStrategyAddresses[1] (optional) /// addresses[n]: initStrategyAddresses[n - 2] (optional) /// @param nums All uint values that strategy requires for initialization. Min array length is 0. /// @param ticks All int24 values that strategy requires for initialization. Min array length is 0. function initialize(address[] memory addresses, uint[] memory nums, int24[] memory ticks) external; /// @notice Invest strategy assets. Amounts of assets must be already on strategy contract balance. /// Only vault can call this. /// @param amounts Anounts of strategy assets /// @return value Liquidity value or underlying token amount function depositAssets(uint[] memory amounts) external returns (uint value); /// @notice Invest underlying asset. Asset must be already on strategy contract balance. /// Only vault can call this. /// @param amount Amount of underlying asset to invest /// @return amountsConsumed Cosumed amounts of invested assets function depositUnderlying(uint amount) external returns (uint[] memory amountsConsumed); /// @dev For specified amount of shares and assets_, withdraw strategy assets from farm/pool/staking and send to receiver if possible /// Only vault can call this. /// @param assets_ Here we give the user a choice of assets to withdraw if strategy support it /// @param value Part of strategy total value to withdraw /// @param receiver User address /// @return amountsOut Amounts of assets sent to user function withdrawAssets( address[] memory assets_, uint value, address receiver ) external returns (uint[] memory amountsOut); /// @notice Wothdraw underlying invested and send to receiver /// Only vault can call this. /// @param amount Ampunt of underlying asset to withdraw /// @param receiver User of vault which withdraw underlying from the vault function withdrawUnderlying(uint amount, address receiver) external; /// @dev For specified amount of shares, transfer strategy assets from contract balance and send to receiver if possible /// This method is called by vault w/o underlying on triggered fuse mode. /// Only vault can call this. /// @param amount Ampunt of liquidity value that user withdraw /// @param totalAmount Total amount of strategy liquidity /// @param receiver User of vault which withdraw assets /// @return amountsOut Amounts of strategy assets sent to user function transferAssets( uint amount, uint totalAmount, address receiver ) external returns (uint[] memory amountsOut); /// @notice Execute HardWork /// During HardWork strategy claiming revenue and processing it. /// Only vault can call this. function doHardWork() external; /// @notice Emergency stop investing by strategy, withdraw liquidity without rewards. /// This action triggers FUSE mode. /// Only governance or multisig can call this. function emergencyStopInvesting() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; /// @notice On-chain price quoter and swapper by predefined routes /// @author Alien Deployer (https://github.com/a17) /// @author Jude (https://github.com/iammrjude) /// @author JodsMigel (https://github.com/JodsMigel) /// @author 0xhokugava (https://github.com/0xhokugava) interface ISwapper { event Swap(address indexed tokenIn, address indexed tokenOut, uint amount); event PoolAdded(PoolData poolData, bool assetAdded); event PoolRemoved(address token); event BlueChipAdded(PoolData poolData); event ThresholdChanged(address[] tokenIn, uint[] thresholdAmount); event BlueChipPoolRemoved(address tokenIn, address tokenOut); //region ----- Custom Errors ----- error UnknownAMMAdapter(); error LessThenThreshold(uint minimumAmount); error NoRouteFound(); error NoRoutesForAssets(); //endregion -- Custom Errors ----- struct PoolData { address pool; address ammAdapter; address tokenIn; address tokenOut; } struct AddPoolData { address pool; string ammAdapterId; address tokenIn; address tokenOut; } /// @notice All assets in pools added to Swapper /// @return Addresses of assets function assets() external view returns (address[] memory); /// @notice All blue chip assets in blue chip pools added to Swapper /// @return Addresses of blue chip assets function bcAssets() external view returns (address[] memory); /// @notice All assets in Swapper /// @return Addresses of assets and blue chip assets function allAssets() external view returns (address[] memory); /// @notice Add pools with largest TVL /// @param pools Largest pools with AMM adapter addresses /// @param rewrite Rewrite pool for tokenIn function addPools(PoolData[] memory pools, bool rewrite) external; /// @notice Add pools with largest TVL /// @param pools Largest pools with AMM adapter ID string /// @param rewrite Rewrite pool for tokenIn function addPools(AddPoolData[] memory pools, bool rewrite) external; /// @notice Add largest pools with the most popular tokens on the current network /// @param pools_ PoolData array with pool, tokens and AMM adapter address /// @param rewrite Change exist pool records function addBlueChipsPools(PoolData[] memory pools_, bool rewrite) external; /// @notice Add largest pools with the most popular tokens on the current network /// @param pools_ AddPoolData array with pool, tokens and AMM adapter string ID /// @param rewrite Change exist pool records function addBlueChipsPools(AddPoolData[] memory pools_, bool rewrite) external; /// @notice Retrieves pool data for a specified token swap in Blue Chip Pools. /// @dev This function provides information about the pool associated with the specified input and output tokens. /// @param tokenIn The input token address. /// @param tokenOut The output token address. /// @return poolData The data structure containing information about the Blue Chip Pool. /// @custom:opcodes view function blueChipsPools(address tokenIn, address tokenOut) external view returns (PoolData memory poolData); /// @notice Set swap threshold for token /// @dev Prevents dust swap. /// @param tokenIn Swap input token /// @param thresholdAmount Minimum amount of token for executing swap function setThresholds(address[] memory tokenIn, uint[] memory thresholdAmount) external; /// @notice Swap threshold for token /// @param token Swap input token /// @return threshold_ Minimum amount of token for executing swap function threshold(address token) external view returns (uint threshold_); /// @notice Price of given tokenIn against tokenOut /// @param tokenIn Swap input token /// @param tokenOut Swap output token /// @param amount Amount of tokenIn. If provide zero then amount is 1.0. /// @return Amount of tokenOut with decimals of tokenOut function getPrice(address tokenIn, address tokenOut, uint amount) external view returns (uint); /// @notice Return price the first poolData.tokenIn against the last poolData.tokenOut in decimals of tokenOut. /// @param route Array of pool address, swapper address tokenIn, tokenOut /// @param amount Amount of tokenIn. If provide zero then amount is 1.0. function getPriceForRoute(PoolData[] memory route, uint amount) external view returns (uint); /// @notice Check possibility of swap tokenIn for tokenOut /// @param tokenIn Swap input token /// @param tokenOut Swap output token /// @return Swap route exists function isRouteExist(address tokenIn, address tokenOut) external view returns (bool); /// @notice Build route for swap. No reverts inside. /// @param tokenIn Swap input token /// @param tokenOut Swap output token /// @return route Array of pools for swap tokenIn to tokenOut. Zero length indicate an error. /// @return errorMessage Possible reason why the route was not found. Empty for success routes. function buildRoute( address tokenIn, address tokenOut ) external view returns (PoolData[] memory route, string memory errorMessage); /// @notice Sell tokenIn for tokenOut /// @dev Assume approve on this contract exist /// @param tokenIn Swap input token /// @param tokenOut Swap output token /// @param amount Amount of tokenIn for swap. /// @param priceImpactTolerance Price impact tolerance. Must include fees at least. Denominator is 100_000. function swap(address tokenIn, address tokenOut, uint amount, uint priceImpactTolerance) external; /// @notice Swap by predefined route /// @param route Array of pool address, swapper address tokenIn, tokenOut. /// TokenIn from first item will be swaped to tokenOut of last . /// @param amount Amount of first item tokenIn. /// @param priceImpactTolerance Price impact tolerance. Must include fees at least. Denominator is 100_000. function swapWithRoute(PoolData[] memory route, uint amount, uint priceImpactTolerance) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; /// @notice Creating vaults, upgrading vaults and strategies, vault list, farms and strategy logics management /// @author Alien Deployer (https://github.com/a17) /// @author Jude (https://github.com/iammrjude) /// @author JodsMigel (https://github.com/JodsMigel) /// @author HCrypto7 (https://github.com/hcrypto7) interface IFactory { //region ----- Custom Errors ----- error VaultImplementationIsNotAvailable(); error VaultNotAllowedToDeploy(); error StrategyImplementationIsNotAvailable(); error StrategyLogicNotAllowedToDeploy(); error YouDontHaveEnoughTokens(uint userBalance, uint requireBalance, address payToken); error SuchVaultAlreadyDeployed(bytes32 key); error NotActiveVault(); error UpgradeDenied(bytes32 _hash); error AlreadyLastVersion(bytes32 _hash); error NotStrategy(); error BoostDurationTooLow(); error BoostAmountTooLow(); error BoostAmountIsZero(); //endregion ----- Custom Errors ----- //region ----- Events ----- event VaultAndStrategy( address indexed deployer, string vaultType, string strategyId, address vault, address strategy, string name, string symbol, address[] assets, bytes32 deploymentKey, uint vaultManagerTokenId ); event StrategyProxyUpgraded(address proxy, address oldImplementation, address newImplementation); event VaultProxyUpgraded(address proxy, address oldImplementation, address newImplementation); event VaultConfigChanged( string type_, address implementation, bool deployAllowed, bool upgradeAllowed, bool newVaultType ); event StrategyLogicConfigChanged( string id, address implementation, bool deployAllowed, bool upgradeAllowed, bool newStrategy ); event VaultStatus(address indexed vault, uint newStatus); event NewFarm(Farm[] farms); event UpdateFarm(uint id, Farm farm); event SetStrategyAvailableInitParams(string id, address[] initAddresses, uint[] initNums, int24[] initTicks); event AliasNameChanged(address indexed operator, address indexed tokenAddress, string newAliasName); //endregion -- Events ----- //region ----- Data types ----- /// @custom:storage-location erc7201:stability.Factory struct FactoryStorage { /// @inheritdoc IFactory mapping(bytes32 typeHash => VaultConfig) vaultConfig; /// @inheritdoc IFactory mapping(bytes32 idHash => StrategyLogicConfig) strategyLogicConfig; /// @inheritdoc IFactory mapping(bytes32 deploymentKey => address vaultProxy) deploymentKey; /// @inheritdoc IFactory mapping(address vault => uint status) vaultStatus; /// @inheritdoc IFactory mapping(address address_ => bool isStrategy_) isStrategy; EnumerableSet.Bytes32Set vaultTypeHashes; EnumerableSet.Bytes32Set strategyLogicIdHashes; mapping(uint week => mapping(uint builderPermitTokenId => uint vaultsBuilt)) vaultsBuiltByPermitTokenId; address[] deployedVaults; Farm[] farms; /// @inheritdoc IFactory mapping(bytes32 idHash => StrategyAvailableInitParams) strategyAvailableInitParams; mapping(address tokenAddress => string aliasName) aliasNames; } struct VaultConfig { string vaultType; address implementation; bool deployAllowed; bool upgradeAllowed; uint buildingPrice; } struct StrategyLogicConfig { string id; address implementation; bool deployAllowed; bool upgradeAllowed; bool farming; uint tokenId; } struct Farm { uint status; address pool; string strategyLogicId; address[] rewardAssets; address[] addresses; uint[] nums; int24[] ticks; } struct StrategyAvailableInitParams { address[] initAddresses; uint[] initNums; int24[] initTicks; } //endregion -- Data types ----- //region ----- View functions ----- /// @notice All vaults deployed by the factory /// @return Vault proxy addresses function deployedVaults() external view returns (address[] memory); /// @notice Total vaults deployed function deployedVaultsLength() external view returns (uint); /// @notice Get vault by VaultManager tokenId /// @param id Vault array index. Same as tokenId of VaultManager NFT /// @return Address of VaultProxy function deployedVault(uint id) external view returns (address); /// @notice All farms known by the factory in current network function farms() external view returns (Farm[] memory); /// @notice Total farms known by the factory in current network function farmsLength() external view returns (uint); /// @notice Farm data by farm index /// @param id Index of farm function farm(uint id) external view returns (Farm memory); /// @notice Strategy logic settings /// @param idHash keccak256 hash of strategy logic string ID /// @return config Strategy logic settings function strategyLogicConfig(bytes32 idHash) external view returns (StrategyLogicConfig memory config); /// @notice All known strategies /// @return Array of keccak256 hashes of strategy logic string ID function strategyLogicIdHashes() external view returns (bytes32[] memory); // todo remove, use new function without calculating vault symbol on the fly for not initialized vaults // factory required that special functionally only internally, not for interface function getStrategyData( string memory vaultType, address strategyAddress, address bbAsset ) external view returns ( string memory strategyId, address[] memory assets, string[] memory assetsSymbols, string memory specificName, string memory vaultSymbol ); /// @dev Get best asset of assets to be strategy exchange asset function getExchangeAssetIndex(address[] memory assets) external view returns (uint); /// @notice Deployment key of created vault /// @param deploymentKey_ Hash of concatenated unique vault and strategy initialization parameters /// @return Address of deployed vault function deploymentKey(bytes32 deploymentKey_) external view returns (address); /// @notice Calculating deployment key based on unique vault and strategy initialization parameters /// @param vaultType Vault type string /// @param strategyId Strategy logic Id string /// @param vaultInitAddresses Vault initizlization addresses for deployVaultAndStrategy method /// @param vaultInitNums Vault initizlization uint numbers for deployVaultAndStrategy method /// @param strategyInitAddresses Strategy initizlization addresses for deployVaultAndStrategy method /// @param strategyInitNums Strategy initizlization uint numbers for deployVaultAndStrategy method /// @param strategyInitTicks Strategy initizlization int24 ticks for deployVaultAndStrategy method function getDeploymentKey( string memory vaultType, string memory strategyId, address[] memory vaultInitAddresses, uint[] memory vaultInitNums, address[] memory strategyInitAddresses, uint[] memory strategyInitNums, int24[] memory strategyInitTicks ) external returns (bytes32); /// @notice Available variants of new vault for creating. /// The structure of the function's output values is complex, /// but after parsing them, the front end has all the data to generate a list of vaults to create. /// @return desc Descriptions of the strategy for making money /// @return vaultType Vault type strings. Output values are matched by index with previous array. /// @return strategyId Strategy logic ID strings. Output values are matched by index with previous array. /// @return initIndexes Map of start and end indexes in next 5 arrays. Output values are matched by index with previous array. /// [0] Start index in vaultInitAddresses /// [1] End index in vaultInitAddresses /// [2] Start index in vaultInitNums /// [3] End index in vaultInitNums /// [4] Start index in strategyInitAddresses /// [5] End index in strategyInitAddresses /// [6] Start index in strategyInitNums /// [7] End index in strategyInitNums /// [8] Start index in strategyInitTicks /// [9] End index in strategyInitTicks /// @return vaultInitAddresses Vault initizlization addresses for deployVaultAndStrategy method for all building variants. /// @return vaultInitNums Vault initizlization uint numbers for deployVaultAndStrategy method for all building variants. /// @return strategyInitAddresses Strategy initizlization addresses for deployVaultAndStrategy method for all building variants. /// @return strategyInitNums Strategy initizlization uint numbers for deployVaultAndStrategy method for all building variants. /// @return strategyInitTicks Strategy initizlization int24 ticks for deployVaultAndStrategy method for all building variants. function whatToBuild() external view returns ( string[] memory desc, string[] memory vaultType, string[] memory strategyId, uint[10][] memory initIndexes, address[] memory vaultInitAddresses, uint[] memory vaultInitNums, address[] memory strategyInitAddresses, uint[] memory strategyInitNums, int24[] memory strategyInitTicks ); /// @notice Governance and multisig can set a vault status other than Active - the default status. /// HardWorker only works with active vaults. /// @return status Constant from VaultStatusLib function vaultStatus(address vault) external view returns (uint status); /// @notice Check that strategy proxy deployed by the Factory /// @param address_ Address of contract /// @return This address is our strategy proxy function isStrategy(address address_) external view returns (bool); /// @notice How much vaults was built by builderPermitToken NFT tokenId in week /// @param week Week index (timestamp / (86400 * 7)) /// @param builderPermitTokenId Token ID of buildingPermitToken NFT /// @return vaultsBuilt Vaults built function vaultsBuiltByPermitTokenId( uint week, uint builderPermitTokenId ) external view returns (uint vaultsBuilt); /// @notice Data on all factory strategies. /// The output values are matched by index in the arrays. /// @return id Strategy logic ID strings /// @return deployAllowed New vaults can be deployed /// @return upgradeAllowed Strategy can be upgraded /// @return farming It is farming strategy (earns farming/gauge rewards) /// @return tokenId Token ID of StrategyLogic NFT /// @return tokenURI StrategyLogic NFT tokenId metadata and on-chain image /// @return extra Strategy color, background color and other extra data function strategies() external view returns ( string[] memory id, bool[] memory deployAllowed, bool[] memory upgradeAllowed, bool[] memory farming, uint[] memory tokenId, string[] memory tokenURI, bytes32[] memory extra ); /// @notice Get config of vault type /// @param typeHash Keccak256 hash of vault type string /// @return vaultType Vault type string /// @return implementation Vault implementation address /// @return deployAllowed New vaults can be deployed /// @return upgradeAllowed Vaults can be upgraded /// @return buildingPrice Price of building new vault function vaultConfig(bytes32 typeHash) external view returns ( string memory vaultType, address implementation, bool deployAllowed, bool upgradeAllowed, uint buildingPrice ); /// @notice Data on all factory vault types /// The output values are matched by index in the arrays. /// @return vaultType Vault type string /// @return implementation Address of vault implemented logic /// @return deployAllowed New vaults can be deployed /// @return upgradeAllowed Vaults can be upgraded /// @return buildingPrice Price of building new vault /// @return extra Vault type color, background color and other extra data function vaultTypes() external view returns ( string[] memory vaultType, address[] memory implementation, bool[] memory deployAllowed, bool[] memory upgradeAllowed, uint[] memory buildingPrice, bytes32[] memory extra ); /// @notice Initialization strategy params store function strategyAvailableInitParams(bytes32 idHash) external view returns (StrategyAvailableInitParams memory); /// @notice Retrieves the alias name associated with a given address /// @param tokenAddress_ The address to query for its alias name /// @return The alias name associated with the provided address function getAliasName(address tokenAddress_) external view returns (string memory); //endregion -- View functions ----- //region ----- Write functions ----- /// @notice Main method of the Factory - new vault creation by user. /// @param vaultType Vault type ID string /// @param strategyId Strategy logic ID string /// Different types of vaults and strategies have different lengths of input arrays. /// @param vaultInitAddresses Addresses for vault initialization /// @param vaultInitNums Numbers for vault initialization /// @param strategyInitAddresses Addresses for strategy initialization /// @param strategyInitNums Numbers for strategy initialization /// @param strategyInitTicks Ticks for strategy initialization /// @return vault Deployed VaultProxy address /// @return strategy Deployed StrategyProxy address function deployVaultAndStrategy( string memory vaultType, string memory strategyId, address[] memory vaultInitAddresses, uint[] memory vaultInitNums, address[] memory strategyInitAddresses, uint[] memory strategyInitNums, int24[] memory strategyInitTicks ) external returns (address vault, address strategy); /// @notice Upgrade vault proxy. Can be called by any address. /// @param vault Address of vault proxy for upgrade function upgradeVaultProxy(address vault) external; /// @notice Upgrade strategy proxy. Can be called by any address. /// @param strategy Address of strategy proxy for upgrade function upgradeStrategyProxy(address strategy) external; /// @notice Add farm to factory /// @param farms_ Settings and data required to work with the farm. function addFarms(Farm[] memory farms_) external; /// @notice Update farm /// @param id Farm index /// @param farm_ Settings and data required to work with the farm. function updateFarm(uint id, Farm memory farm_) external; /// @notice Initial addition or change of vault type settings. /// Operator can add new vault type. Governance or multisig can change existing vault type config. /// @param vaultConfig_ Vault type settings function setVaultConfig(VaultConfig memory vaultConfig_) external; /// @notice Initial addition or change of strategy logic settings. /// Operator can add new strategy logic. Governance or multisig can change existing logic config. /// @param config Strategy logic settings /// @param developer Strategy developer is receiver of minted StrategyLogic NFT on initial addition function setStrategyLogicConfig(StrategyLogicConfig memory config, address developer) external; /// @notice Governance and multisig can set a vault status other than Active - the default status. /// @param vaults Addresses of vault proxy /// @param statuses New vault statuses. Constant from VaultStatusLib function setVaultStatus(address[] memory vaults, uint[] memory statuses) external; /// @notice Initial addition or change of strategy available init params /// @param id Strategy ID string /// @param initParams Init params variations that will be parsed by strategy function setStrategyAvailableInitParams(string memory id, StrategyAvailableInitParams memory initParams) external; /// @notice Assigns a new alias name to a specific address /// @dev This function may require certain permissions to be called successfully. /// @param tokenAddress_ The address to assign an alias name to /// @param aliasName_ The alias name to assign to the given address function setAliasName(address tokenAddress_, string memory aliasName_) external; //endregion -- Write functions ----- }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; /// @dev Combining oracle and DeX spot prices /// @author Alien Deployer (https://github.com/a17) /// @author Jude (https://github.com/iammrjude) /// @author JodsMigel (https://github.com/JodsMigel) interface IPriceReader { //region ----- Events ----- event AdapterAdded(address adapter); event AdapterRemoved(address adapter); //endregion -- Events ----- /// @notice Price of asset /// @dev Price of 1.0 amount of asset in USD /// @param asset Address of asset /// @return price USD price with 18 decimals /// @return trusted Price from oracle function getPrice(address asset) external view returns (uint price, bool trusted); /// @notice Get USD price of specified assets and amounts /// @param assets_ Addresses of assets /// @param amounts_ Amount of asset. Index of asset same as in previous parameter. /// @return total Total USD value with 18 decimals /// @return assetAmountPrice USD price of asset amount. Index of assetAmountPrice same as in assets_ parameters. /// @return assetPrice USD price of asset. Index of assetAmountPrice same as in assets_ parameters. /// @return trusted True if only oracle prices was used for calculation. function getAssetsPrice( address[] memory assets_, uint[] memory amounts_ ) external view returns (uint total, uint[] memory assetAmountPrice, uint[] memory assetPrice, bool trusted); /// @notice Add oracle adapter to PriceReader /// Only operator (multisig is operator too) can add adapter /// @param adapter_ Address of price oracle proxy function addAdapter(address adapter_) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; import "./IStrategy.sol"; /// @notice Vault core interface. /// Derived implementations can be effective for building tokenized vaults with single or multiple underlying liquidity mining position. /// Fungible, static non-fungible and actively re-balancing liquidity is supported, as well as single token liquidity provided to lending protocols. /// Vaults can be used for active concentrated liquidity management and market making. /// @author Jude (https://github.com/iammrjude) /// @author JodsMigel (https://github.com/JodsMigel) interface IVault is IERC165 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error NotEnoughBalanceToPay(); error FuseTrigger(); error ExceedSlippage(uint mintToUser, uint minToMint); error ExceedSlippageExactAsset(address asset, uint mintToUser, uint minToMint); error ExceedMaxSupply(uint maxSupply); error NotEnoughAmountToInitSupply(uint mintAmount, uint initialShares); error WaitAFewBlocks(); error StrategyZeroDeposit(); error NotSupported(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ event DepositAssets(address indexed account, address[] assets, uint[] amounts, uint mintAmount); event WithdrawAssets( address indexed sender, address indexed owner, address[] assets, uint sharesAmount, uint[] amountsOut ); event HardWorkGas(uint gasUsed, uint gasCost, bool compensated); event DoHardWorkOnDepositChanged(bool oldValue, bool newValue); event MaxSupply(uint maxShares); event VaultName(string newName); event VaultSymbol(string newSymbol); event MintFees( uint vaultManagerReceiverFee, uint strategyLogicReceiverFee, uint ecosystemRevenueReceiverFee, uint multisigReceiverFee ); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DATA TYPES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @custom:storage-location erc7201:stability.VaultBase struct VaultBaseStorage { /// @dev Prevents manipulations with deposit and withdraw in short time. /// For simplification we are setup new withdraw request on each deposit/transfer. mapping(address msgSender => uint blockNumber) withdrawRequests; /// @inheritdoc IVault IStrategy strategy; /// @inheritdoc IVault uint maxSupply; /// @inheritdoc IVault uint tokenId; /// @inheritdoc IVault bool doHardWorkOnDeposit; /// @dev Immutable vault type ID string _type; /// @dev Changed ERC20 name string changedName; /// @dev Changed ERC20 symbol string changedSymbol; } /// @title Vault Initialization Data /// @notice Data structure containing parameters for initializing a new vault. /// @dev This struct is commonly used as a parameter for the `initialize` function in vault contracts. /// @param platform Platform address providing access control, infrastructure addresses, fee settings, and upgrade capability. /// @param strategy Immutable strategy proxy used by the vault. /// @param name ERC20 name for the vault token. /// @param symbol ERC20 symbol for the vault token. /// @param tokenId NFT ID associated with the VaultManager. /// @param vaultInitAddresses Array of addresses used during vault initialization. /// @param vaultInitNums Array of uint values corresponding to initialization parameters. struct VaultInitializationData { address platform; address strategy; string name; string symbol; uint tokenId; address[] vaultInitAddresses; uint[] vaultInitNums; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* VIEW FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Immutable vault type ID function vaultType() external view returns (string memory); /// @return uniqueInitAddresses Return required unique init addresses /// @return uniqueInitNums Return required unique init nums function getUniqueInitParamLength() external view returns (uint uniqueInitAddresses, uint uniqueInitNums); /// @notice Vault type extra data /// @return Vault type color, background color and other extra data function extra() external view returns (bytes32); /// @notice Immutable strategy proxy used by the vault /// @return Linked strategy function strategy() external view returns (IStrategy); /// @notice Max supply of shares in the vault. /// Since the starting share price is $1, this ceiling can be considered as an approximate TVL limit. /// @return Max total supply of vault function maxSupply() external view returns (uint); /// @dev VaultManager token ID. This tokenId earn feeVaultManager provided by Platform. function tokenId() external view returns (uint); /// @dev Trigger doHardwork on invest action. Enabled by default. function doHardWorkOnDeposit() external view returns (bool); /// @dev USD price of share with 18 decimals. /// ONLY FOR OFF-CHAIN USE. /// Not trusted vault share price can be manipulated. /// @return price_ Price of 1e18 shares with 18 decimals precision /// @return trusted True means oracle price, false means AMM spot price function price() external view returns (uint price_, bool trusted); /// @dev USD price of assets managed by strategy with 18 decimals /// ONLY FOR OFF-CHAIN USE. /// Not trusted TVL can be manipulated. /// @return tvl_ Total USD value of final assets in vault /// @return trusted True means TVL calculated based only on oracle prices, false means AMM spot price was used. function tvl() external view returns (uint tvl_, bool trusted); /// @dev Calculation of consumed amounts, shares amount and liquidity/underlying value for provided available amounts of strategy assets /// @param assets_ Assets suitable for vault strategy. Can be strategy assets, underlying asset or specific set of assets depending on strategy logic. /// @param amountsMax Available amounts of assets_ that user wants to invest in vault /// @return amountsConsumed Amounts of strategy assets that can be deposited by providing amountsMax /// @return sharesOut Amount of vault shares that will be minted /// @return valueOut Liquidity value or underlying token amount that will be received by the strategy function previewDepositAssets( address[] memory assets_, uint[] memory amountsMax ) external view returns (uint[] memory amountsConsumed, uint sharesOut, uint valueOut); /// @notice All available data on the latest declared APR (annual percentage rate) /// @return totalApr Total APR of investing money to vault. 18 decimals: 1e18 - +100% per year. /// @return strategyApr Strategy investmnt APR declared on last HardWork. /// @return assetsWithApr Assets with underlying APR /// @return assetsAprs Underlying APR of asset function getApr() external view returns (uint totalApr, uint strategyApr, address[] memory assetsWithApr, uint[] memory assetsAprs); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* WRITE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mint fee shares callback /// @param revenueAssets Assets returned by _claimRevenue function that was earned during HardWork /// @param revenueAmounts Assets amounts returned from _claimRevenue function that was earned during HardWork /// Only strategy can call this function hardWorkMintFeeCallback(address[] memory revenueAssets, uint[] memory revenueAmounts) external; /// @dev Deposit final assets (pool assets) to the strategy and minting of vault shares. /// If the strategy interacts with a pool or farms through an underlying token, then it will be minted. /// Emits a {DepositAssets} event with consumed amounts. /// @param assets_ Assets suitable for the strategy. Can be strategy assets, underlying asset or specific set of assets depending on strategy logic. /// @param amountsMax Available amounts of assets_ that user wants to invest in vault /// @param minSharesOut Slippage tolerance. Minimal shares amount which must be received by user. /// @param receiver Receiver of deposit. If receiver is zero address, receiver is msg.sender. function depositAssets( address[] memory assets_, uint[] memory amountsMax, uint minSharesOut, address receiver ) external; /// @dev Burning shares of vault and obtaining strategy assets. /// @param assets_ Assets suitable for the strategy. Can be strategy assets, underlying asset or specific set of assets depending on strategy logic. /// @param amountShares Shares amount for burning /// @param minAssetAmountsOut Slippage tolerance. Minimal amounts of strategy assets that user must receive. /// @return Amount of assets for withdraw. It's related to assets_ one-by-one. function withdrawAssets( address[] memory assets_, uint amountShares, uint[] memory minAssetAmountsOut ) external returns (uint[] memory); /// @dev Burning shares of vault and obtaining strategy assets. /// @param assets_ Assets suitable for the strategy. Can be strategy assets, underlying asset or specific set of assets depending on strategy logic. /// @param amountShares Shares amount for burning /// @param minAssetAmountsOut Slippage tolerance. Minimal amounts of strategy assets that user must receive. /// @param receiver Receiver of assets /// @param owner Owner of vault shares /// @return Amount of assets for withdraw. It's related to assets_ one-by-one. function withdrawAssets( address[] memory assets_, uint amountShares, uint[] memory minAssetAmountsOut, address receiver, address owner ) external returns (uint[] memory); /// @dev Setting of vault capacity /// @param maxShares If totalSupply() exceeds this value, deposits will not be possible function setMaxSupply(uint maxShares) external; /// @dev If activated will call doHardWork on strategy on some deposit actions /// @param value HardWork on deposit is enabled function setDoHardWorkOnDeposit(bool value) external; /// @notice Initialization function for the vault. /// @dev This function is usually called by the Factory during the creation of a new vault. /// @param vaultInitializationData Data structure containing parameters for vault initialization. function initialize(VaultInitializationData memory vaultInitializationData) external; /// @dev Calling the strategy HardWork by operator with optional compensation for spent gas from the vault balance function doHardWork() external; /// @dev Changing ERC20 name of vault function setName(string calldata newName) external; /// @dev Changing ERC20 symbol of vault function setSymbol(string calldata newSymbol) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; import "./IVault.sol"; /// @notice Interface of Rewarding Vault /// @author Alien Deployer (https://github.com/a17) /// @author JodsMigel (https://github.com/JodsMigel) /// @author 0xhokugava (https://github.com/0xhokugava) interface IRVault is IVault { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ error NotAllowed(); error Overflow(uint maxAmount); error RTNotFound(); error NoBBToken(); error NotAllowedBBToken(); error IncorrectNums(); error ZeroToken(); error ZeroVestingDuration(); error TooHighCompoundRation(); error RewardIsTooSmall(); // error RewardIsTooBig(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ event RewardAdded(address rewardToken, uint reward); event RewardPaid(address indexed user, address rewardToken, uint reward); event SetRewardsRedirect(address owner, address receiver); event AddedRewardToken(address indexed token, uint indexed tokenIndex); event CompoundRatio(uint compoundRatio_); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DATA TYPES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @custom:storage-location erc7201:stability.RVaultBase struct RVaultBaseStorage { /// @inheritdoc IRVault mapping(uint tokenIndex => address rewardToken) rewardToken; /// @inheritdoc IRVault mapping(uint tokenIndex => uint durationSeconds) duration; /// @inheritdoc IRVault mapping(address owner => address receiver) rewardsRedirect; /// @dev Timestamp value when current period of rewards will be ended mapping(uint tokenIndex => uint finishTimestamp) periodFinishForToken; /// @dev Reward rate in normal circumstances is distributed rewards divided on duration mapping(uint tokenIndex => uint rewardRate) rewardRateForToken; /// @dev Last rewards snapshot time. Updated on each share movements mapping(uint tokenIndex => uint lastUpdateTimestamp) lastUpdateTimeForToken; /// @dev Rewards snapshot calculated from rewardPerToken(rt). Updated on each share movements mapping(uint tokenIndex => uint rewardPerTokenStored) rewardPerTokenStoredForToken; /// @dev User personal reward rate snapshot. Updated on each share movements mapping(uint tokenIndex => mapping(address user => uint rewardPerTokenPaid)) userRewardPerTokenPaidForToken; /// @dev User personal earned reward snapshot. Updated on each share movements mapping(uint tokenIndex => mapping(address user => uint earned)) rewardsForToken; /// @inheritdoc IRVault uint rewardTokensTotal; /// @inheritdoc IRVault uint compoundRatio; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* VIEW FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice All vault rewarding tokens /// @return Reward token addresses function rewardTokens() external view returns (address[] memory); /// @return Total of bbToken + boost reward tokens function rewardTokensTotal() external view returns (uint); /// @notice Immutable reward buy-back token with tokenIndex 0 function bbToken() external view returns (address); /// @dev A mapping of reward tokens that able to be distributed to this contract. /// Token with index 0 always is bbToken. function rewardToken(uint tokenIndex) external view returns (address rewardToken_); /// @notice Re-investing ratio /// @dev Changeable ratio of revenue part for re-investing. Other part goes to rewarding by bbToken. /// @return Ratio of re-investing part of revenue. Denominator is 100_000. function compoundRatio() external view returns (uint); /// @notice Vesting period for distribution reward /// @param tokenIndex Index of rewarding token /// @return durationSeconds Duration for distributing of notified reward function duration(uint tokenIndex) external view returns (uint durationSeconds); /// @notice Return earned rewards for specific token and account /// Accurate value returns only after updateRewards call /// ((balanceOf(account) /// * (rewardPerToken - userRewardPerTokenPaidForToken)) / 10**18) + rewardsForToken function earned(uint rewardTokenIndex, address account) external view returns (uint); /// @notice Return reward per token ratio by reward token address /// rewardPerTokenStoredForToken + ( /// (lastTimeRewardApplicable - lastUpdateTimeForToken) /// * rewardRateForToken * 10**18 / totalSupply) /// @param rewardTokenIndex Index of reward token /// @return Return reward per token ratio by reward token address function rewardPerToken(uint rewardTokenIndex) external view returns (uint); /// @dev Receiver of rewards can be set by multisig when owner cant claim rewards himself /// @param owner Token owner address /// @return receiver Return reward's receiver function rewardsRedirect(address owner) external view returns (address receiver); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* WRITE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @notice Filling vault with rewards /// @dev Update rewardRateForToken /// If period ended: reward / duration /// else add leftover to the reward amount and refresh the period /// (reward + ((periodFinishForToken - block.timestamp) * rewardRateForToken)) / duration /// @param tokenIndex Index of rewarding token /// @param amount Amount for rewarding function notifyTargetRewardAmount(uint tokenIndex, uint amount) external; /// @notice Update and Claim all rewards for caller function getAllRewards() external; /// @notice Update and Claim rewards for specific token /// @param rt Index of reward token function getReward(uint rt) external; /// @dev All rewards for given owner could be claimed for receiver address. /// @param owner Token owner address /// @param receiver New reward's receiver function setRewardsRedirect(address owner, address receiver) external; /// @notice Update and Claim all rewards for given owner address. Send them to predefined receiver. /// @param owner Token owner address function getAllRewardsAndRedirect(address owner) external; /// @notice Update and Claim all rewards for the given owner. /// Sender should have allowance for push rewards for the owner. /// @param owner Token owner address function getAllRewardsFor(address owner) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; /// @dev Interface of proxy contract for a vault implementation interface IVaultProxy { //region ----- Custom Errors ----- error ProxyForbidden(); //endregion -- Custom Errors ----- /// @notice Initialize vault proxy by Factory /// @param type_ Vault type ID string function initProxy(string memory type_) external; /// @notice Upgrade vault implementation if available and allowed /// Anyone can execute vault upgrade function upgrade() external; /// @notice Current vault implementation /// @return Address of vault implementation contract function implementation() external view returns (address); /// @notice Vault type hash /// @return keccan256 hash of vault type ID string function vaultTypeHash() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; /// @dev Interface of proxy contract for a strategy implementation interface IStrategyProxy { /// @notice Initialize strategy proxy by Factory /// @param id Strategy logic ID string function initStrategyProxy(string memory id) external; /// @notice Upgrade strategy implementation if available and allowed /// Anyone can execute strategy upgrade function upgrade() external; /// @notice Current strategy implementation /// @return Address of strategy implementation contract function implementation() external view returns (address); /// @notice Strategy logic hash /// @return keccan256 hash of strategy logic ID string function strategyImplementationLogicIdHash() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; library ConstantsLib { uint internal constant DENOMINATOR = 100_000; address internal constant DEAD_ADDRESS = 0xdEad000000000000000000000000000000000000; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.20; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position is the index of the value in the `values` array plus 1. // Position 0 is used to mean a value is not in the set. mapping(bytes32 value => uint256) _positions; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._positions[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot uint256 position = set._positions[value]; if (position != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) set._positions[lastValue] = position; } // Delete the slot where the moved value was stored set._values.pop(); // Delete the tracked position for the deleted slot delete set._positions[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
{ "remappings": [ "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@solady/=lib/solady/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/", "solady/=lib/solady/", "openzeppelin-contracts/=lib/openzeppelin-contracts/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "shanghai", "viaIR": false, "libraries": { "src/core/libs/CommonLib.sol": { "CommonLib": "0x4f76ADd676c04ecA837130CeB58Bc173de8799dE" }, "src/core/libs/DeployerLib.sol": { "DeployerLib": "0x29613385F8808A04E593163a2867f3F3D4a1BD8B" }, "src/core/libs/FactoryLib.sol": { "FactoryLib": "0x06e0912b4f2E36cfcF9556478352AFC2d991919F" }, "src/core/libs/FactoryNamingLib.sol": { "FactoryNamingLib": "0x3110a397362465b6Ad45703DE9DEa2CC2Ae6C3B3" }, "src/core/libs/StrategyLogicLib.sol": { "StrategyLogicLib": "0xCA26bF5d5B610EB3E48041Dd7eb5Ce57475fB878" }, "src/core/libs/VaultBaseLib.sol": { "VaultBaseLib": "0xD728c9C834985f583B1d0C29f84D80d1EF75A609" }, "src/core/libs/VaultManagerLib.sol": { "VaultManagerLib": "0xE080ED61824494De0b191597e907Ee458F47c64b" }, "src/strategies/libs/LPStrategyLib.sol": { "LPStrategyLib": "0xda05a4EC440C6E3A253d37652F1907118c06079a" }, "src/strategies/libs/StrategyLib.sol": { "StrategyLib": "0xc2dE381a066FD7282aF33378664161a8fc180796" }, "src/strategies/libs/UniswapV3MathLib.sol": { "UniswapV3MathLib": "0xbbc63ee4a06bf1F2432ccC4d70103e3D465fcA39" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"}],"name":"AlreadyLastVersion","type":"error"},{"inputs":[],"name":"BoostAmountIsZero","type":"error"},{"inputs":[],"name":"BoostAmountTooLow","type":"error"},{"inputs":[],"name":"BoostDurationTooLow","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"NoRouteFound","type":"error"},{"inputs":[],"name":"NoRoutesForAssets","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"}],"name":"UpgradeDenied","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"proxy","type":"address"},{"indexed":false,"internalType":"address","name":"oldImplementation","type":"address"},{"indexed":false,"internalType":"address","name":"newImplementation","type":"address"}],"name":"StrategyProxyUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"type_","type":"string"},{"indexed":false,"internalType":"address","name":"implementation","type":"address"},{"indexed":false,"internalType":"bool","name":"deployAllowed","type":"bool"},{"indexed":false,"internalType":"bool","name":"upgradeAllowed","type":"bool"},{"indexed":false,"internalType":"bool","name":"newVaultType","type":"bool"}],"name":"VaultConfigChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"proxy","type":"address"},{"indexed":false,"internalType":"address","name":"oldImplementation","type":"address"},{"indexed":false,"internalType":"address","name":"newImplementation","type":"address"}],"name":"VaultProxyUpgraded","type":"event"},{"inputs":[],"name":"BOOST_REWARD_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"vaultType","type":"string"},{"internalType":"string","name":"strategyId","type":"string"},{"internalType":"address[]","name":"initVaultAddresses","type":"address[]"},{"internalType":"uint256[]","name":"initVaultNums","type":"uint256[]"},{"internalType":"address[]","name":"initStrategyAddresses","type":"address[]"},{"internalType":"uint256[]","name":"initStrategyNums","type":"uint256[]"},{"internalType":"int24[]","name":"initStrategyTicks","type":"int24[]"},{"internalType":"uint8[5]","name":"usedValuesForKey","type":"uint8[5]"}],"name":"getDeploymentKey","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"platform","type":"address"},{"internalType":"address[]","name":"assets","type":"address[]"}],"name":"getExchangeAssetIndex","outputs":[{"internalType":"uint256","name":"exchangeAssetIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"vaultType","type":"string"},{"internalType":"string","name":"id","type":"string"},{"internalType":"string","name":"symbols","type":"string"},{"internalType":"string","name":"specificName","type":"string"},{"internalType":"address[]","name":"vaultInitAddresses","type":"address[]"}],"name":"getName","outputs":[{"internalType":"string","name":"name","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"platform","type":"address"}],"name":"whatToBuild","outputs":[{"internalType":"string[]","name":"desc","type":"string[]"},{"internalType":"string[]","name":"vaultType","type":"string[]"},{"internalType":"string[]","name":"strategyId","type":"string[]"},{"internalType":"uint256[10][]","name":"initIndexes","type":"uint256[10][]"},{"internalType":"address[]","name":"vaultInitAddresses","type":"address[]"},{"internalType":"uint256[]","name":"vaultInitNums","type":"uint256[]"},{"internalType":"address[]","name":"strategyInitAddresses","type":"address[]"},{"internalType":"uint256[]","name":"strategyInitNums","type":"uint256[]"},{"internalType":"int24[]","name":"strategyInitTicks","type":"int24[]"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
615315610035600b8282823980515f1a60731461002957634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040526004361061009b575f3560e01c8063a1cb54301161006e578063a1cb54301461013b578063d0d34fa41461015a578063d563b9001461017a578063d8613a9e14610192578063e551e36a146101a5575f80fd5b806305091ded1461009f5780631b4c3fdd146100d35780632c1172ae146100f4578063781760531461011c575b5f80fd5b8180156100aa575f80fd5b506100be6100b9366004613eb5565b6101b8565b60405190151581526020015b60405180910390f35b8180156100de575f80fd5b506100f26100ed366004614062565b6102d2565b005b610107610102366004614108565b61097e565b6040516100ca9998979695949392919061426c565b818015610127575f80fd5b506100f2610136366004614378565b61262f565b818015610146575f80fd5b506100f2610155366004614378565b612901565b61016d6101683660046143a6565b612aea565b6040516100ca9190614461565b61018462278d0081565b6040519081526020016100ca565b6101846101a036600461454a565b612c61565b6101846101b336600461466a565b612eb3565b80516040515f919082906101d09083906020016146b6565b60408051601f1981840301815291815281516020928301205f8181529288905291208551919250859181906102059082614754565b506020820151600182018054604085015160608601511515600160a81b0260ff60a81b19911515600160a01b026001600160a81b03199093166001600160a01b039095169490941791909117169190911790556080909101516002909101555f61027260058701836130c9565b90508061027e57600193505b7f8f5d0835a8539894bd827328bbcb6390206ee0218ad0fac339c627889cebd8a683866020015187604001518860600151856040516102c195949392919061480f565b60405180910390a150505092915050565b6102f560405180606001604052805f151581526020015f81526020015f81525090565b6040805180820182526009815268526577617264696e6760b81b602082015290516310d24b2160e11b8152734f76add676c04eca837130ceb58bc173de8799de916321a496429161034a918891600401614850565b602060405180830381865af4158015610365573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103899190614884565b1515808252806104305750604080518082018252601181527014995dd85c991a5b99c813585b9859d959607a1b602082015290516310d24b2160e11b8152734f76add676c04eca837130ceb58bc173de8799de916321a49642916103f1918891600401614850565b602060405180830381865af415801561040c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104309190614884565b1561097657856001600160a01b031663df6617f8845f815181106104565761045661489f565b60200260200101516040518263ffffffff1660e01b815260040161048991906001600160a01b0391909116815260200190565b5f604051808303815f87803b1580156104a0575f80fd5b505af11580156104b2573d5f803e3d5ffd5b505050505f866001600160a01b03166349b5fdb46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104f3573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061051791906148be565b9050866001600160a01b03166312e0832a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610555573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061057991906148d9565b826020018181525050866001600160a01b031663d515be566040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105be573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e291906148d9565b826040018181525050856001600160a01b031663c2b18aa06040518163ffffffff1660e01b81526004015f60405180830381865afa158015610626573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261064d9190810190614955565b93505f6001855161065e91906149a2565b90505f805b8281101561092c575f876106788360016149b5565b815181106106885761068861489f565b602002602001015190505f865f01516106c457876106a78460016149b5565b815181106106b7576106b761489f565b60200260200101516106c9565b62278d005b905086602001518110156106f05760405163e360740760e01b815260040160405180910390fd5b86515f9061072c5788846107058860016149b5565b61070f91906149b5565b8151811061071f5761071f61489f565b6020026020010151610747565b88848151811061073e5761073e61489f565b60200260200101515b6040516341976e0960e01b81526001600160a01b0385811660048301529192505f918916906341976e09906024016040805180830381865afa15801561078f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107b391906149c8565b50905082670de0b6b3a764000082866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107fd573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061082191906149eb565b61082c90600a614ae6565b61083e86670de0b6b3a7640000614af4565b6108489190614b0b565b6108529190614af4565b61085c9190614b0b565b6108699062015180614af4565b6108739190614b0b565b61087d90876149b5565b9550811561091d5761089a6001600160a01b0385163330856130db565b6108ae6001600160a01b0385168e84613148565b6001600160a01b038d1663828716106108c88760016149b5565b846040518363ffffffff1660e01b81526004016108ef929190918252602082015260400190565b5f604051808303815f87803b158015610906575f80fd5b505af1158015610918573d5f803e3d5ffd5b505050505b50505050806001019050610663565b50805f0361094d5760405163fdd7ae1760e01b815260040160405180910390fd5b83604001518110156109725760405163046e74b760e31b815260040160405180910390fd5b5050505b505050505050565b6060806060806060806060806060610a91604051806104c00160405280606081526020015f8152602001606081526020015f8152602001606081526020015f815260200160608152602001606081526020016060815260200160608152602001606081526020015f81526020015f8152602001606081526020015f81526020016060815260200160608152602001606081526020015f81526020015f81526020015f815260200160608152602001606081526020016060815260200160608152602001606081526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f8b6001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ace573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610af291906148be565b9050806001600160a01b0316630f038dcd6040518163ffffffff1660e01b81526004015f60405180830381865afa158015610b2f573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610b569190810190614b2a565b8083525160208301526040805163438feb4160e11b815290516001600160a01b0383169163871fd682916004808301925f9291908290030181865afa158015610ba1573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610bc89190810190614cb8565b604083018190525160608301525b8160200151826104600151101561148a576040805160c08101825260608082525f6020830181905292820183905281018290526080810182905260a0810191909152816001600160a01b031663c56ebcd6845f015185610460015181518110610c4157610c4161489f565b60200260200101516040518263ffffffff1660e01b8152600401610c6791815260200190565b5f60405180830381865afa158015610c81573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ca89190810190614e48565b905080604001511561147257610cc28d82602001516131d7565b61014088015261012087015261010086015260e085015260c084018190525160a08401525f610160840181905261018084018190525b8360a00151811015611470578360e001518181518110610d1a57610d1a61489f565b60200260200101516001600160401b03811115610d3957610d39613d4a565b604051908082528060200260200182016040528015610d62578160200160208202803683370190505b506102a0850152610100840151805182908110610d8157610d8161489f565b60200260200101516001600160401b03811115610da057610da0613d4a565b604051908082528060200260200182016040528015610dc9578160200160208202803683370190505b506102c08501525f5b8460e001518281518110610de857610de861489f565b6020026020010151811015610e6c5784610120015185610160015181518110610e1357610e1361489f565b6020026020010151856102a001518281518110610e3257610e3261489f565b60200260200101906001600160a01b031690816001600160a01b03168152505084610160018051610e6290614f0f565b9052600101610dd2565b505f5b8461010001518281518110610e8657610e8661489f565b6020026020010151811015610ef65784610140015185610180015181518110610eb157610eb161489f565b6020026020010151856102c001518281518110610ed057610ed061489f565b60200260200101818152505084610180018051610eec90614f0f565b9052600101610e6f565b5081602001516001600160a01b0316632d433b288f6040518263ffffffff1660e01b8152600401610f3691906001600160a01b0391909116815260200190565b5f60405180830381865afa158015610f50573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610f779190810190614fa1565b6102208801526102008701526101e08601526101a085018190525f61024086018190526102608601819052610280860181905290516104808601919091525b808561048001511015611467575f81866101e0015151610fd69190614b0b565b5f610340880181905261036088018190526103808801529050806001600160401b0381111561100757611007613d4a565b604051908082528060200260200182016040528015611030578160200160208202803683370190505b506102e08701525f5b818110156110c857866101e001518761024001518151811061105d5761105d61489f565b6020026020010151876102e00151828151811061107c5761107c61489f565b60200260200101906001600160a01b031690816001600160a01b031681525050866102400180516110ac90614f0f565b9052610340870180516110be90614f0f565b9052600101611039565b5081866102000151516110db9190614b0b565b9050806001600160401b038111156110f5576110f5613d4a565b60405190808252806020026020018201604052801561111e578160200160208202803683370190505b506103008701525f5b818110156111a2578661020001518761026001518151811061114b5761114b61489f565b6020026020010151876103000151828151811061116a5761116a61489f565b6020026020010181815250508661026001805161118690614f0f565b90526103608701805161119890614f0f565b9052600101611127565b5081866102200151516111b59190614b0b565b9050806001600160401b038111156111cf576111cf613d4a565b6040519080825280602002602001820160405280156111f8578160200160208202803683370190505b506103208701525f5b8181101561128457866102200151876102800151815181106112255761122561489f565b602002602001015187610320015182815181106112445761124461489f565b602002602001019060020b908160020b815250508661028001805161126890614f0f565b90526103808701805161127a90614f0f565b9052600101611201565b505f6113078760c00151858151811061129f5761129f61489f565b6020026020010151865f0151896102a001518a6102c001518b6102e001518c61030001518d61032001516040518060a00160405280600160ff1681526020015f60ff168152602001600160ff168152602001600160ff1681526020015f60ff16815250612c61565b604051637d474fa360e01b8152600481018290529091505f906001600160a01b03881690637d474fa390602401602060405180830381865afa15801561134f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061137391906148be565b6001600160a01b03160361144e57866103a001805161139190614f0f565b905260e08701518051859081106113aa576113aa61489f565b6020026020010151876103c0018181516113c491906149b5565b9052506101008701518051859081106113df576113df61489f565b6020026020010151876103e0018181516113f991906149b5565b905250610340870151610400880180516114149083906149b5565b9052506103608701516104208801805161142f9083906149b5565b9052506103808701516104408801805161144a9083906149b5565b9052505b50508461048001805161146090614f0f565b9052610fb6565b50600101610cf8565b505b508161046001805161148390614f0f565b9052610bd6565b816103a001516001600160401b038111156114a7576114a7613d4a565b6040519080825280602002602001820160405280156114da57816020015b60608152602001906001900390816114c55790505b509a50816103a001516001600160401b038111156114fa576114fa613d4a565b60405190808252806020026020018201604052801561152d57816020015b60608152602001906001900390816115185790505b509950816103a001516001600160401b0381111561154d5761154d613d4a565b60405190808252806020026020018201604052801561158057816020015b606081526020019060019003908161156b5790505b509850816103a001516001600160401b038111156115a0576115a0613d4a565b6040519080825280602002602001820160405280156115d957816020015b6115c6613d0d565b8152602001906001900390816115be5790505b509750816103c001516001600160401b038111156115f9576115f9613d4a565b604051908082528060200260200182016040528015611622578160200160208202803683370190505b509650816103e001516001600160401b0381111561164257611642613d4a565b60405190808252806020026020018201604052801561166b578160200160208202803683370190505b5095508161040001516001600160401b0381111561168b5761168b613d4a565b6040519080825280602002602001820160405280156116b4578160200160208202803683370190505b5094508161042001516001600160401b038111156116d4576116d4613d4a565b6040519080825280602002602001820160405280156116fd578160200160208202803683370190505b5093508161044001516001600160401b0381111561171d5761171d613d4a565b604051908082528060200260200182016040528015611746578160200160208202803683370190505b505f6103a084018190526103c084018190526103e0840181905261040084018190526104208401819052610440840181905261046084015292505b81602001518261046001511015612620576040805160c08101825260608082525f6020830181905292820183905281018290526080810182905260a0810191909152816001600160a01b031663c56ebcd6845f0151856104600151815181106117ec576117ec61489f565b60200260200101516040518263ffffffff1660e01b815260040161181291815260200190565b5f60405180830381865afa15801561182c573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526118539190810190614e48565b90508060400151156126085761186d8d82602001516131d7565b61014088015261012087015261010086015260e085015260c084018190525160a08401525f610160840181905261018084018190525b8360a00151811015612606578360e0015181815181106118c5576118c561489f565b60200260200101516001600160401b038111156118e4576118e4613d4a565b60405190808252806020026020018201604052801561190d578160200160208202803683370190505b506102a085015261010084015180518290811061192c5761192c61489f565b60200260200101516001600160401b0381111561194b5761194b613d4a565b604051908082528060200260200182016040528015611974578160200160208202803683370190505b506102c08501525f5b8460e0015182815181106119935761199361489f565b6020026020010151811015611a1757846101200151856101600151815181106119be576119be61489f565b6020026020010151856102a0015182815181106119dd576119dd61489f565b60200260200101906001600160a01b031690816001600160a01b03168152505084610160018051611a0d90614f0f565b905260010161197d565b505f5b8461010001518281518110611a3157611a3161489f565b6020026020010151811015611aa15784610140015185610180015181518110611a5c57611a5c61489f565b6020026020010151856102c001518281518110611a7b57611a7b61489f565b60200260200101818152505084610180018051611a9790614f0f565b9052600101611a1a565b5081602001516001600160a01b0316632d433b288f6040518263ffffffff1660e01b8152600401611ae191906001600160a01b0391909116815260200190565b5f60405180830381865afa158015611afb573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611b229190810190614fa1565b6102208801526102008701526101e08601526101a085018190525f61024086018190526102608601819052610280860181905290516101c08601526104808501525b836101c0015184610480015110156125fe575f846101c00151856101e0015151611b8e9190614b0b565b5f610340870181905261036087018190526103808701529050806001600160401b03811115611bbf57611bbf613d4a565b604051908082528060200260200182016040528015611be8578160200160208202803683370190505b506102e08601525f5b81811015611c8057856101e0015186610240015181518110611c1557611c1561489f565b6020026020010151866102e001518281518110611c3457611c3461489f565b60200260200101906001600160a01b031690816001600160a01b03168152505085610240018051611c6490614f0f565b905261034086018051611c7690614f0f565b9052600101611bf1565b50846101c0015185610200015151611c989190614b0b565b9050806001600160401b03811115611cb257611cb2613d4a565b604051908082528060200260200182016040528015611cdb578160200160208202803683370190505b506103008601525f5b81811015611d5f5785610200015186610260015181518110611d0857611d0861489f565b60200260200101518661030001518281518110611d2757611d2761489f565b60200260200101818152505085610260018051611d4390614f0f565b905261036086018051611d5590614f0f565b9052600101611ce4565b50846101c0015185610220015151611d779190614b0b565b9050806001600160401b03811115611d9157611d91613d4a565b604051908082528060200260200182016040528015611dba578160200160208202803683370190505b506103208601525f5b81811015611e465785610220015186610280015181518110611de757611de761489f565b60200260200101518661032001518281518110611e0657611e0661489f565b602002602001019060020b908160020b8152505085610280018051611e2a90614f0f565b905261038086018051611e3c90614f0f565b9052600101611dc3565b505f611ec98660c001518481518110611e6157611e6161489f565b6020026020010151855f0151886102a00151896102c001518a6102e001518b61030001518c61032001516040518060a00160405280600160ff1681526020015f60ff168152602001600160ff168152602001600160ff1681526020015f60ff16815250612c61565b604051637d474fa360e01b8152600481018290529091505f906001600160a01b03871690637d474fa390602401602060405180830381865afa158015611f11573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f3591906148be565b6001600160a01b0316036125e557856101a0015186610480015181518110611f5f57611f5f61489f565b60200260200101518f876103a0015181518110611f7e57611f7e61489f565b60200260200101819052508560c001518381518110611f9f57611f9f61489f565b60200260200101518e876103a0015181518110611fbe57611fbe61489f565b6020026020010181905250835f01518d876103a0015181518110611fe457611fe461489f565b6020026020010181905250856103c001518c876103a001518151811061200c5761200c61489f565b60200260200101515f600a81106120255761202561489f565b602002015260e08601518051849081106120415761204161489f565b6020026020010151866103c0015161205991906149b5565b8c876103a00151815181106120705761207061489f565b60200260200101516001600a811061208a5761208a61489f565b60200201526103e08601516103a08701518d518e919081106120ae576120ae61489f565b60200260200101516002600a81106120c8576120c861489f565b60200201526101008601518051849081106120e5576120e561489f565b6020026020010151866103e001516120fd91906149b5565b8c876103a00151815181106121145761211461489f565b60200260200101516003600a811061212e5761212e61489f565b60200201526104008601516103a08701518d518e919081106121525761215261489f565b60200260200101516004600a811061216c5761216c61489f565b602002015261034086015161040087015161218791906149b5565b8c876103a001518151811061219e5761219e61489f565b60200260200101516005600a81106121b8576121b861489f565b60200201526104208601516103a08701518d518e919081106121dc576121dc61489f565b60200260200101516006600a81106121f6576121f661489f565b602002015261036086015161042087015161221191906149b5565b8c876103a00151815181106122285761222861489f565b60200260200101516007600a81106122425761224261489f565b60200201526104408601516103a08701518d518e919081106122665761226661489f565b60200260200101516008600a81106122805761228061489f565b602002015261038086015161044087015161229b91906149b5565b8c876103a00151815181106122b2576122b261489f565b60200260200101516009600a81106122cc576122cc61489f565b60200201525f5b8660e0015184815181106122e9576122e961489f565b602002602001015181101561235957866102a00151818151811061230f5761230f61489f565b60200260200101518c82896103c0015161232991906149b5565b815181106123395761233961489f565b6001600160a01b03909216602092830291909101909101526001016122d3565b505f5b86610100015184815181106123735761237361489f565b60200260200101518110156123d657866102c0015181815181106123995761239961489f565b60200260200101518b82896103e001516123b391906149b5565b815181106123c3576123c361489f565b602090810291909101015260010161235c565b505f5b86610340015181101561244757866102e0015181815181106123fd576123fd61489f565b60200260200101518a8289610400015161241791906149b5565b815181106124275761242761489f565b6001600160a01b03909216602092830291909101909101526001016123d9565b505f5b8661036001518110156124ab57866103000151818151811061246e5761246e61489f565b6020026020010151898289610420015161248891906149b5565b815181106124985761249861489f565b602090810291909101015260010161244a565b505f5b8661038001518110156125175786610320015181815181106124d2576124d261489f565b602002602001015188828961044001516124ec91906149b5565b815181106124fc576124fc61489f565b60029290920b602092830291909101909101526001016124ae565b50856103a001805161252890614f0f565b905260e08601518051849081106125415761254161489f565b6020026020010151866103c00181815161255b91906149b5565b9052506101008601518051849081106125765761257661489f565b6020026020010151866103e00181815161259091906149b5565b905250610340860151610400870180516125ab9083906149b5565b905250610360860151610420870180516125c69083906149b5565b905250610380860151610440870180516125e19083906149b5565b9052505b5050836104800180516125f790614f0f565b9052611b64565b6001016118a3565b505b508161046001805161261990614f0f565b9052611781565b50509193959799909294969850565b5f8190505f816001600160a01b0316630146056d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612670573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061269491906148d9565b90505f826001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126f791906148be565b90505f855f015f8481526020019081526020015f206040518060a00160405290815f82018054612726906146d1565b80601f0160208091040260200160405190810160405280929190818152602001828054612752906146d1565b801561279d5780601f106127745761010080835404028352916020019161279d565b820191905f5260205f20905b81548152906001019060200180831161278057829003601f168201915b505050918352505060018201546001600160a01b03811660208084019190915260ff600160a01b8304811615156040850152600160a81b9092049091161515606080840191909152600290930154608090920191909152820151908201519192509061282457604051630301207f60e21b8152600481018590526024015b60405180910390fd5b806001600160a01b0316836001600160a01b031603612859576040516316c7522960e31b81526004810185905260240161281b565b846001600160a01b031663d55ec6976040518163ffffffff1660e01b81526004015f604051808303815f87803b158015612891575f80fd5b505af11580156128a3573d5f803e3d5ffd5b5050604080516001600160a01b03808b16825280881660208301528516918101919091527f74cd4f776fca6a39fc6f0983929e27ca9b19899c0c1827713393042bbe2afb16925060600190505b60405180910390a150505050505050565b5f8190505f816001600160a01b031663c29df70a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612942573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061296691906148d9565b5f81815260018601602090815260408083208151635c60da1b60e01b81529151949550936001600160a01b03871692635c60da1b92600480820193918290030181865afa1580156129b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129dd91906148be565b60018301549091506001600160a01b03811690600160a81b900460ff16612a1a57604051630301207f60e21b81526004810185905260240161281b565b806001600160a01b0316826001600160a01b031603612a4f576040516316c7522960e31b81526004810185905260240161281b565b846001600160a01b031663d55ec6976040518163ffffffff1660e01b81526004015f604051808303815f87803b158015612a87575f80fd5b505af1158015612a99573d5f803e3d5ffd5b5050604080516001600160a01b03808b16825280871660208301528516918101919091527f746871013d9225e5b11b13b9256515b47fa5378b085f1ba9b07b5f5112480ccf925060600190506128f0565b60608385604051602001612aff929190615046565b60408051601f1981840301815260208381019092525f9092528451908501209091507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47014612b6c578083604051602001612b5a929190615097565b60405160208183030381529060405290505b604080518082019091526009815268526577617264696e6760b81b6020918201528651908701207f9ebab07909aaa4cdae2d5e985d99720616df0dc6818db31d46ea1437e7afe57f01612c585780825f81518110612bcc57612bcc61489f565b60200260200101516001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa158015612c0e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612c3591908101906150d2565b604051602001612c46929190615103565b60405160208183030381529060405290505b95945050505050565b5f8089604051602001612c7491906146b6565b60408051601f198184030181529082905280516020918201209250612c9b918b91016146b6565b60408051808303601f1901815291905280516020909101208851845192909101915f919060ff16811115612cd05750835160ff165b80821015612d0a57898281518110612cea57612cea61489f565b60200260200101516001600160a01b031683019250816001019150612cd0565b508751602085015160ff16811115612d265750602084015160ff165b5f91505b80821015612d5b57888281518110612d4457612d4461489f565b602002602001015183019250816001019150612d2a565b508651604085015160ff16811115612d775750604084015160ff165b5f91505b80821015612db557878281518110612d9557612d9561489f565b60200260200101516001600160a01b031683019250816001019150612d7b565b508551606085015160ff16811115612dd15750606084015160ff165b5f91505b80821015612e0657868281518110612def57612def61489f565b602002602001015183019250816001019150612dd5565b508451608085015160ff16811115612e225750608084015160ff165b5f91505b80821015612ea3575f868381518110612e4157612e4161489f565b602002602001015160020b1215612e7657858281518110612e6457612e6461489f565b602002602001015160020b5f03612e94565b858281518110612e8857612e8861489f565b602002602001015160020b5b83019250816001019150612e26565b50909a9950505050505050505050565b5f80836001600160a01b03166354aa3d086040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ef1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f1591906148be565b83519091505f5b81811015612f6857826001600160a01b0316858281518110612f4057612f4061489f565b60200260200101516001600160a01b031603612f605792506130c3915050565b600101612f1c565b505f1992505f5f1990505f866001600160a01b0316632b3297f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612faf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fd391906148be565b90505f5b8381101561309c575f826001600160a01b0316636e8811028984815181106130015761300161489f565b6020026020010151886040518363ffffffff1660e01b815260040161303c9291906001600160a01b0392831681529116602082015260400190565b5f60405180830381865afa158015613056573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261307d9190810190615152565b50805190915084811015613092578094508297505b5050600101612fd7565b505f1985036130be576040516305fcedf360e01b815260040160405180910390fd5b505050505b92915050565b5f6130d48383613ab9565b9392505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526131429186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050613b05565b50505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526131998482613b6b565b613142576040516001600160a01b0384811660248301525f60448301526131cd91869182169063095ea7b390606401613110565b6131428482613b05565b606080606080606061320d6040518060a00160405280606081526020015f81526020015f81526020015f81526020015f81525090565b866001600160a01b031663fdff667c6040518163ffffffff1660e01b81526004015f60405180830381865afa158015613248573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261326f9190810190615259565b808252516080820152604080516360997e8560e01b815290515f916001600160a01b038b16916360997e859160048082019286929091908290030181865afa1580156132bd573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526132e4919081019061528a565b5080519091505f5b836080015181101561357c57734f76add676c04eca837130ceb58bc173de8799de6321a49642855f015183815181106133275761332761489f565b60200260200101516040518060400160405280600b81526020016a436f6d706f756e64696e6760a81b8152506040518363ffffffff1660e01b8152600401613370929190614850565b602060405180830381865af415801561338b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133af9190614884565b156133ca578360200180516133c390614f0f565b9052613574565b734f76add676c04eca837130ceb58bc173de8799de6321a49642855f015183815181106133f9576133f961489f565b602002602001015160405180604001604052806009815260200168526577617264696e6760b81b8152506040518363ffffffff1660e01b8152600401613440929190614850565b602060405180830381865af415801561345b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061347f9190614884565b806135425750734f76add676c04eca837130ceb58bc173de8799de6321a49642855f015183815181106134b4576134b461489f565b60200260200101516040518060400160405280601181526020017014995dd85c991a5b99c813585b9859d959607a1b8152506040518363ffffffff1660e01b8152600401613503929190614850565b602060405180830381865af415801561351e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135429190614884565b1561357457818460200181815161355991906149b5565b9052506040840180518391906135709083906149b5565b9052505b6001016132ec565b5082602001516001600160401b0381111561359957613599613d4a565b6040519080825280602002602001820160405280156135cc57816020015b60608152602001906001900390816135b75790505b50975082602001516001600160401b038111156135eb576135eb613d4a565b604051908082528060200260200182016040528015613614578160200160208202803683370190505b50965082602001516001600160401b0381111561363357613633613d4a565b60405190808252806020026020018201604052801561365c578160200160208202803683370190505b50955082604001516001600160401b0381111561367b5761367b613d4a565b6040519080825280602002602001820160405280156136a4578160200160208202803683370190505b50945082606001516001600160401b038111156136c3576136c3613d4a565b6040519080825280602002602001820160405280156136ec578160200160208202803683370190505b5093506136f7613d2c565b5f5b8460800151811015613aaa57734f76add676c04eca837130ceb58bc173de8799de6321a49642865f015183815181106137345761373461489f565b60200260200101516040518060400160405280600b81526020016a436f6d706f756e64696e6760a81b8152506040518363ffffffff1660e01b815260040161377d929190614850565b602060405180830381865af4158015613798573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137bc9190614884565b156138245784518051829081106137d5576137d561489f565b60200260200101518a835f600381106137f0576137f061489f565b6020020151815181106138055761380561489f565b60209081029190910101528151829061381d90614f0f565b9052613aa2565b734f76add676c04eca837130ceb58bc173de8799de6321a49642865f015183815181106138535761385361489f565b602002602001015160405180604001604052806009815260200168526577617264696e6760b81b8152506040518363ffffffff1660e01b815260040161389a929190614850565b602060405180830381865af41580156138b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906138d99190614884565b8061399c5750734f76add676c04eca837130ceb58bc173de8799de6321a49642865f0151838151811061390e5761390e61489f565b60200260200101516040518060400160405280601181526020017014995dd85c991a5b99c813585b9859d959607a1b8152506040518363ffffffff1660e01b815260040161395d929190614850565b602060405180830381865af4158015613978573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061399c9190614884565b15613aa2575f5b83811015613aa05785518051839081106139bf576139bf61489f565b60200260200101518b845f600381106139da576139da61489f565b6020020151815181106139ef576139ef61489f565b6020026020010181905250848181518110613a0c57613a0c61489f565b60200260200101518884600160038110613a2857613a2861489f565b602002015181518110613a3d57613a3d61489f565b6001600160a01b03929092166020928302919091019091015282518a516001918c918110613a6d57613a6d61489f565b602090810291909101015282518390613a8590614f0f565b9052602083018051613a9690614f0f565b90526001016139a3565b505b6001016136f9565b50505050509295509295909350565b5f818152600183016020526040812054613afe57508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556130c3565b505f6130c3565b5f613b196001600160a01b03841683613c08565b905080515f14158015613b3d575080806020019051810190613b3b9190614884565b155b15613b6657604051635274afe760e01b81526001600160a01b038416600482015260240161281b565b505050565b5f805f846001600160a01b031684604051613b8691906146b6565b5f604051808303815f865af19150503d805f8114613bbf576040519150601f19603f3d011682016040523d82523d5f602084013e613bc4565b606091505b5091509150818015613bee575080511580613bee575080806020019051810190613bee9190614884565b8015612c585750505050506001600160a01b03163b151590565b60606130d483835f845f80856001600160a01b03168486604051613c2c91906146b6565b5f6040518083038185875af1925050503d805f8114613c66576040519150601f19603f3d011682016040523d82523d5f602084013e613c6b565b606091505b5091509150613c7b868383613c85565b9695505050505050565b606082613c9a57613c9582613ce1565b6130d4565b8151158015613cb157506001600160a01b0384163b155b15613cda57604051639996b31560e01b81526001600160a01b038516600482015260240161281b565b50806130d4565b805115613cf15780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b50565b604051806101400160405280600a906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b634e487b7160e01b5f52604160045260245ffd5b60405160a081016001600160401b0381118282101715613d8057613d80613d4a565b60405290565b60405160e081016001600160401b0381118282101715613d8057613d80613d4a565b60405160c081016001600160401b0381118282101715613d8057613d80613d4a565b604051608081016001600160401b0381118282101715613d8057613d80613d4a565b604051601f8201601f191681016001600160401b0381118282101715613e1457613e14613d4a565b604052919050565b5f6001600160401b03821115613e3457613e34613d4a565b50601f01601f191660200190565b5f82601f830112613e51575f80fd5b8135613e64613e5f82613e1c565b613dec565b818152846020838601011115613e78575f80fd5b816020850160208301375f918101602001919091529392505050565b6001600160a01b0381168114613d0a575f80fd5b8015158114613d0a575f80fd5b5f8060408385031215613ec6575f80fd5b8235915060208301356001600160401b0380821115613ee3575f80fd5b9084019060a08287031215613ef6575f80fd5b613efe613d5e565b823582811115613f0c575f80fd5b613f1888828601613e42565b82525060208301359150613f2b82613e94565b81602082015260408301359150613f4182613ea8565b81604082015260608301359150613f5782613ea8565b816060820152608083013560808201528093505050509250929050565b5f6001600160401b03821115613f8c57613f8c613d4a565b5060051b60200190565b5f82601f830112613fa5575f80fd5b81356020613fb5613e5f83613f74565b8083825260208201915060208460051b870101935086841115613fd6575f80fd5b602086015b84811015613ffb578035613fee81613e94565b8352918301918301613fdb565b509695505050505050565b5f82601f830112614015575f80fd5b81356020614025613e5f83613f74565b8083825260208201915060208460051b870101935086841115614046575f80fd5b602086015b84811015613ffb578035835291830191830161404b565b5f805f805f60a08688031215614076575f80fd5b853561408181613e94565b9450602086013561409181613e94565b935060408601356001600160401b03808211156140ac575f80fd5b6140b889838a01613e42565b945060608801359150808211156140cd575f80fd5b6140d989838a01613f96565b935060808801359150808211156140ee575f80fd5b506140fb88828901614006565b9150509295509295909350565b5f60208284031215614118575f80fd5b81356130d481613e94565b5f5b8381101561413d578181015183820152602001614125565b50505f910152565b5f815180845261415c816020860160208601614123565b601f01601f19169290920160200192915050565b5f8282518085526020808601955060208260051b840101602086015f5b848110156141bb57601f198684030189526141a9838351614145565b9884019892509083019060010161418d565b5090979650505050505050565b5f815180845260208085019450602084015f5b838110156142005781516001600160a01b0316875295820195908201906001016141db565b509495945050505050565b5f815180845260208085019450602084015f5b838110156142005781518752958201959082019060010161421e565b5f815180845260208085019450602084015f5b8381101561420057815160020b8752958201959082019060010161424d565b5f61012080835261427f8184018d614170565b9050602083820381850152614294828d614170565b915083820360408501526142a8828c614170565b84810360608601528a51808252828c019350908201905f5b81811015614301578451835f5b600a8110156142ea578251825291860191908601906001016142cd565b5050509383019361014092909201916001016142c0565b50508481036080860152614315818b6141c8565b9250505082810360a084015261432b818861420b565b905082810360c084015261433f81876141c8565b905082810360e0840152614353818661420b565b9050828103610100840152614368818561423a565b9c9b505050505050505050505050565b5f8060408385031215614389575f80fd5b82359150602083013561439b81613e94565b809150509250929050565b5f805f805f60a086880312156143ba575f80fd5b85356001600160401b03808211156143d0575f80fd5b6143dc89838a01613e42565b965060208801359150808211156143f1575f80fd5b6143fd89838a01613e42565b95506040880135915080821115614412575f80fd5b61441e89838a01613e42565b94506060880135915080821115614433575f80fd5b61443f89838a01613e42565b93506080880135915080821115614454575f80fd5b506140fb88828901613f96565b602081525f6130d46020830184614145565b8060020b8114613d0a575f80fd5b5f82601f830112614490575f80fd5b813560206144a0613e5f83613f74565b8083825260208201915060208460051b8701019350868411156144c1575f80fd5b602086015b84811015613ffb5780356144d981614473565b83529183019183016144c6565b60ff81168114613d0a575f80fd5b5f82601f830112614503575f80fd5b61450b613d5e565b8060a084018581111561451c575f80fd5b845b8181101561453f578035614531816144e6565b84526020938401930161451e565b509095945050505050565b5f805f805f805f80610180898b031215614562575f80fd5b88356001600160401b0380821115614578575f80fd5b6145848c838d01613e42565b995060208b0135915080821115614599575f80fd5b6145a58c838d01613e42565b985060408b01359150808211156145ba575f80fd5b6145c68c838d01613f96565b975060608b01359150808211156145db575f80fd5b6145e78c838d01614006565b965060808b01359150808211156145fc575f80fd5b6146088c838d01613f96565b955060a08b013591508082111561461d575f80fd5b6146298c838d01614006565b945060c08b013591508082111561463e575f80fd5b5061464b8b828c01614481565b92505061465b8a60e08b016144f4565b90509295985092959890939650565b5f806040838503121561467b575f80fd5b823561468681613e94565b915060208301356001600160401b038111156146a0575f80fd5b6146ac85828601613f96565b9150509250929050565b5f82516146c7818460208701614123565b9190910192915050565b600181811c908216806146e557607f821691505b60208210810361470357634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115613b6657805f5260205f20601f840160051c8101602085101561472e5750805b601f840160051c820191505b8181101561474d575f815560010161473a565b5050505050565b81516001600160401b0381111561476d5761476d613d4a565b6147818161477b84546146d1565b84614709565b602080601f8311600181146147b4575f841561479d5750858301515b5f19600386901b1c1916600185901b178555610976565b5f85815260208120601f198616915b828110156147e2578886015182559484019460019091019084016147c3565b50858210156147ff57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b60a081525f61482160a0830188614145565b6001600160a01b0396909616602083015250921515604084015290151560608301521515608090910152919050565b604081525f6148626040830185614145565b8281036020840152612c588185614145565b805161487f81613ea8565b919050565b5f60208284031215614894575f80fd5b81516130d481613ea8565b634e487b7160e01b5f52603260045260245ffd5b805161487f81613e94565b5f602082840312156148ce575f80fd5b81516130d481613e94565b5f602082840312156148e9575f80fd5b5051919050565b5f82601f8301126148ff575f80fd5b8151602061490f613e5f83613f74565b8083825260208201915060208460051b870101935086841115614930575f80fd5b602086015b84811015613ffb57805161494881613e94565b8352918301918301614935565b5f60208284031215614965575f80fd5b81516001600160401b0381111561497a575f80fd5b614986848285016148f0565b949350505050565b634e487b7160e01b5f52601160045260245ffd5b818103818111156130c3576130c361498e565b808201808211156130c3576130c361498e565b5f80604083850312156149d9575f80fd5b82519150602083015161439b81613ea8565b5f602082840312156149fb575f80fd5b81516130d4816144e6565b600181815b80851115614a4057815f1904821115614a2657614a2661498e565b80851615614a3357918102915b93841c9390800290614a0b565b509250929050565b5f82614a56575060016130c3565b81614a6257505f6130c3565b8160018114614a785760028114614a8257614a9e565b60019150506130c3565b60ff841115614a9357614a9361498e565b50506001821b6130c3565b5060208310610133831016604e8410600b8410161715614ac1575081810a6130c3565b614acb8383614a06565b805f1904821115614ade57614ade61498e565b029392505050565b5f6130d460ff841683614a48565b80820281158282048414176130c3576130c361498e565b5f82614b2557634e487b7160e01b5f52601260045260245ffd5b500490565b5f6020808385031215614b3b575f80fd5b82516001600160401b03811115614b50575f80fd5b8301601f81018513614b60575f80fd5b8051614b6e613e5f82613f74565b81815260059190911b82018301908381019087831115614b8c575f80fd5b928401925b82841015614baa57835182529284019290840190614b91565b979650505050505050565b5f82601f830112614bc4575f80fd5b8151614bd2613e5f82613e1c565b818152846020838601011115614be6575f80fd5b614986826020830160208701614123565b5f82601f830112614c06575f80fd5b81516020614c16613e5f83613f74565b8083825260208201915060208460051b870101935086841115614c37575f80fd5b602086015b84811015613ffb5780518352918301918301614c3c565b5f82601f830112614c62575f80fd5b81516020614c72613e5f83613f74565b8083825260208201915060208460051b870101935086841115614c93575f80fd5b602086015b84811015613ffb578051614cab81614473565b8352918301918301614c98565b5f6020808385031215614cc9575f80fd5b82516001600160401b0380821115614cdf575f80fd5b818501915085601f830112614cf2575f80fd5b8151614d00613e5f82613f74565b81815260059190911b83018401908481019088831115614d1e575f80fd5b8585015b83811015614e3b57805185811115614d38575f80fd5b860160e0818c03601f19011215614d4d575f80fd5b614d55613d86565b8882015181526040614d688184016148b3565b8a83015260608084015189811115614d7e575f80fd5b614d8c8f8d83880101614bb5565b8385015250608091508184015189811115614da5575f80fd5b614db38f8d838801016148f0565b82850152505060a08084015189811115614dcb575f80fd5b614dd98f8d838801016148f0565b838501525060c091508184015189811115614df2575f80fd5b614e008f8d83880101614bf7565b82850152505060e083015188811115614e17575f80fd5b614e258e8c83870101614c53565b9183019190915250845250918601918601614d22565b5098975050505050505050565b5f60208284031215614e58575f80fd5b81516001600160401b0380821115614e6e575f80fd5b9083019060c08286031215614e81575f80fd5b614e89613da8565b825182811115614e97575f80fd5b614ea387828601614bb5565b82525060208301519150614eb682613e94565b81602082015260408301519150614ecc82613ea8565b81604082015260608301519150614ee282613ea8565b816060820152614ef460808401614874565b608082015260a083015160a082015280935050505092915050565b5f60018201614f2057614f2061498e565b5060010190565b5f82601f830112614f36575f80fd5b81516020614f46613e5f83613f74565b82815260059290921b84018101918181019086841115614f64575f80fd5b8286015b84811015613ffb5780516001600160401b03811115614f85575f80fd5b614f938986838b0101614bb5565b845250918301918301614f68565b5f805f8060808587031215614fb4575f80fd5b84516001600160401b0380821115614fca575f80fd5b614fd688838901614f27565b95506020870151915080821115614feb575f80fd5b614ff7888389016148f0565b9450604087015191508082111561500c575f80fd5b61501888838901614bf7565b9350606087015191508082111561502d575f80fd5b5061503a87828801614c53565b91505092959194509250565b69029ba30b134b634ba3c960b51b81525f835161506a81600a850160208801614123565b600160fd1b600a91840191820152835161508b81600b840160208801614123565b01600b01949350505050565b5f83516150a8818460208801614123565b600160fd1b90830190815283516150c6816001840160208801614123565b01600101949350505050565b5f602082840312156150e2575f80fd5b81516001600160401b038111156150f7575f80fd5b61498684828501614bb5565b5f8351615114818460208801614123565b600160fd1b9083019081528351615132816001840160208801614123565b66081c995dd85c9960ca1b60019290910191820152600801949350505050565b5f806040808486031215615164575f80fd5b83516001600160401b038082111561517a575f80fd5b818601915086601f83011261518d575f80fd5b8151602061519d613e5f83613f74565b82815260079290921b8401810191818101908a8411156151bb575f80fd5b948201945b83861015615233576080868c0312156151d7575f80fd5b6151df613dca565b86516151ea81613e94565b8152868401516151f981613e94565b818501528688015161520a81613e94565b8189015260608781015161521d81613e94565b90820152825260809590950194908201906151c0565b9189015191975090945050508083111561524b575f80fd5b50506146ac85828601614bb5565b5f60208284031215615269575f80fd5b81516001600160401b0381111561527e575f80fd5b61498684828501614f27565b5f806040838503121561529b575f80fd5b82516001600160401b03808211156152b1575f80fd5b6152bd868387016148f0565b935060208501519150808211156152d2575f80fd5b506146ac85828601614bf756fea264697066735822122066e0519974f18a8866e479e1adf04d9ae5110a8f3cf4d34303208ef772abe59e64736f6c63430008170033
Deployed Bytecode
0x7306e0912b4f2e36cfcf9556478352afc2d991919f301460806040526004361061009b575f3560e01c8063a1cb54301161006e578063a1cb54301461013b578063d0d34fa41461015a578063d563b9001461017a578063d8613a9e14610192578063e551e36a146101a5575f80fd5b806305091ded1461009f5780631b4c3fdd146100d35780632c1172ae146100f4578063781760531461011c575b5f80fd5b8180156100aa575f80fd5b506100be6100b9366004613eb5565b6101b8565b60405190151581526020015b60405180910390f35b8180156100de575f80fd5b506100f26100ed366004614062565b6102d2565b005b610107610102366004614108565b61097e565b6040516100ca9998979695949392919061426c565b818015610127575f80fd5b506100f2610136366004614378565b61262f565b818015610146575f80fd5b506100f2610155366004614378565b612901565b61016d6101683660046143a6565b612aea565b6040516100ca9190614461565b61018462278d0081565b6040519081526020016100ca565b6101846101a036600461454a565b612c61565b6101846101b336600461466a565b612eb3565b80516040515f919082906101d09083906020016146b6565b60408051601f1981840301815291815281516020928301205f8181529288905291208551919250859181906102059082614754565b506020820151600182018054604085015160608601511515600160a81b0260ff60a81b19911515600160a01b026001600160a81b03199093166001600160a01b039095169490941791909117169190911790556080909101516002909101555f61027260058701836130c9565b90508061027e57600193505b7f8f5d0835a8539894bd827328bbcb6390206ee0218ad0fac339c627889cebd8a683866020015187604001518860600151856040516102c195949392919061480f565b60405180910390a150505092915050565b6102f560405180606001604052805f151581526020015f81526020015f81525090565b6040805180820182526009815268526577617264696e6760b81b602082015290516310d24b2160e11b8152734f76add676c04eca837130ceb58bc173de8799de916321a496429161034a918891600401614850565b602060405180830381865af4158015610365573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103899190614884565b1515808252806104305750604080518082018252601181527014995dd85c991a5b99c813585b9859d959607a1b602082015290516310d24b2160e11b8152734f76add676c04eca837130ceb58bc173de8799de916321a49642916103f1918891600401614850565b602060405180830381865af415801561040c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104309190614884565b1561097657856001600160a01b031663df6617f8845f815181106104565761045661489f565b60200260200101516040518263ffffffff1660e01b815260040161048991906001600160a01b0391909116815260200190565b5f604051808303815f87803b1580156104a0575f80fd5b505af11580156104b2573d5f803e3d5ffd5b505050505f866001600160a01b03166349b5fdb46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104f3573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061051791906148be565b9050866001600160a01b03166312e0832a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610555573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061057991906148d9565b826020018181525050866001600160a01b031663d515be566040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105be573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e291906148d9565b826040018181525050856001600160a01b031663c2b18aa06040518163ffffffff1660e01b81526004015f60405180830381865afa158015610626573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261064d9190810190614955565b93505f6001855161065e91906149a2565b90505f805b8281101561092c575f876106788360016149b5565b815181106106885761068861489f565b602002602001015190505f865f01516106c457876106a78460016149b5565b815181106106b7576106b761489f565b60200260200101516106c9565b62278d005b905086602001518110156106f05760405163e360740760e01b815260040160405180910390fd5b86515f9061072c5788846107058860016149b5565b61070f91906149b5565b8151811061071f5761071f61489f565b6020026020010151610747565b88848151811061073e5761073e61489f565b60200260200101515b6040516341976e0960e01b81526001600160a01b0385811660048301529192505f918916906341976e09906024016040805180830381865afa15801561078f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107b391906149c8565b50905082670de0b6b3a764000082866001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107fd573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061082191906149eb565b61082c90600a614ae6565b61083e86670de0b6b3a7640000614af4565b6108489190614b0b565b6108529190614af4565b61085c9190614b0b565b6108699062015180614af4565b6108739190614b0b565b61087d90876149b5565b9550811561091d5761089a6001600160a01b0385163330856130db565b6108ae6001600160a01b0385168e84613148565b6001600160a01b038d1663828716106108c88760016149b5565b846040518363ffffffff1660e01b81526004016108ef929190918252602082015260400190565b5f604051808303815f87803b158015610906575f80fd5b505af1158015610918573d5f803e3d5ffd5b505050505b50505050806001019050610663565b50805f0361094d5760405163fdd7ae1760e01b815260040160405180910390fd5b83604001518110156109725760405163046e74b760e31b815260040160405180910390fd5b5050505b505050505050565b6060806060806060806060806060610a91604051806104c00160405280606081526020015f8152602001606081526020015f8152602001606081526020015f815260200160608152602001606081526020016060815260200160608152602001606081526020015f81526020015f8152602001606081526020015f81526020016060815260200160608152602001606081526020015f81526020015f81526020015f815260200160608152602001606081526020016060815260200160608152602001606081526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f8b6001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ace573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610af291906148be565b9050806001600160a01b0316630f038dcd6040518163ffffffff1660e01b81526004015f60405180830381865afa158015610b2f573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610b569190810190614b2a565b8083525160208301526040805163438feb4160e11b815290516001600160a01b0383169163871fd682916004808301925f9291908290030181865afa158015610ba1573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610bc89190810190614cb8565b604083018190525160608301525b8160200151826104600151101561148a576040805160c08101825260608082525f6020830181905292820183905281018290526080810182905260a0810191909152816001600160a01b031663c56ebcd6845f015185610460015181518110610c4157610c4161489f565b60200260200101516040518263ffffffff1660e01b8152600401610c6791815260200190565b5f60405180830381865afa158015610c81573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ca89190810190614e48565b905080604001511561147257610cc28d82602001516131d7565b61014088015261012087015261010086015260e085015260c084018190525160a08401525f610160840181905261018084018190525b8360a00151811015611470578360e001518181518110610d1a57610d1a61489f565b60200260200101516001600160401b03811115610d3957610d39613d4a565b604051908082528060200260200182016040528015610d62578160200160208202803683370190505b506102a0850152610100840151805182908110610d8157610d8161489f565b60200260200101516001600160401b03811115610da057610da0613d4a565b604051908082528060200260200182016040528015610dc9578160200160208202803683370190505b506102c08501525f5b8460e001518281518110610de857610de861489f565b6020026020010151811015610e6c5784610120015185610160015181518110610e1357610e1361489f565b6020026020010151856102a001518281518110610e3257610e3261489f565b60200260200101906001600160a01b031690816001600160a01b03168152505084610160018051610e6290614f0f565b9052600101610dd2565b505f5b8461010001518281518110610e8657610e8661489f565b6020026020010151811015610ef65784610140015185610180015181518110610eb157610eb161489f565b6020026020010151856102c001518281518110610ed057610ed061489f565b60200260200101818152505084610180018051610eec90614f0f565b9052600101610e6f565b5081602001516001600160a01b0316632d433b288f6040518263ffffffff1660e01b8152600401610f3691906001600160a01b0391909116815260200190565b5f60405180830381865afa158015610f50573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610f779190810190614fa1565b6102208801526102008701526101e08601526101a085018190525f61024086018190526102608601819052610280860181905290516104808601919091525b808561048001511015611467575f81866101e0015151610fd69190614b0b565b5f610340880181905261036088018190526103808801529050806001600160401b0381111561100757611007613d4a565b604051908082528060200260200182016040528015611030578160200160208202803683370190505b506102e08701525f5b818110156110c857866101e001518761024001518151811061105d5761105d61489f565b6020026020010151876102e00151828151811061107c5761107c61489f565b60200260200101906001600160a01b031690816001600160a01b031681525050866102400180516110ac90614f0f565b9052610340870180516110be90614f0f565b9052600101611039565b5081866102000151516110db9190614b0b565b9050806001600160401b038111156110f5576110f5613d4a565b60405190808252806020026020018201604052801561111e578160200160208202803683370190505b506103008701525f5b818110156111a2578661020001518761026001518151811061114b5761114b61489f565b6020026020010151876103000151828151811061116a5761116a61489f565b6020026020010181815250508661026001805161118690614f0f565b90526103608701805161119890614f0f565b9052600101611127565b5081866102200151516111b59190614b0b565b9050806001600160401b038111156111cf576111cf613d4a565b6040519080825280602002602001820160405280156111f8578160200160208202803683370190505b506103208701525f5b8181101561128457866102200151876102800151815181106112255761122561489f565b602002602001015187610320015182815181106112445761124461489f565b602002602001019060020b908160020b815250508661028001805161126890614f0f565b90526103808701805161127a90614f0f565b9052600101611201565b505f6113078760c00151858151811061129f5761129f61489f565b6020026020010151865f0151896102a001518a6102c001518b6102e001518c61030001518d61032001516040518060a00160405280600160ff1681526020015f60ff168152602001600160ff168152602001600160ff1681526020015f60ff16815250612c61565b604051637d474fa360e01b8152600481018290529091505f906001600160a01b03881690637d474fa390602401602060405180830381865afa15801561134f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061137391906148be565b6001600160a01b03160361144e57866103a001805161139190614f0f565b905260e08701518051859081106113aa576113aa61489f565b6020026020010151876103c0018181516113c491906149b5565b9052506101008701518051859081106113df576113df61489f565b6020026020010151876103e0018181516113f991906149b5565b905250610340870151610400880180516114149083906149b5565b9052506103608701516104208801805161142f9083906149b5565b9052506103808701516104408801805161144a9083906149b5565b9052505b50508461048001805161146090614f0f565b9052610fb6565b50600101610cf8565b505b508161046001805161148390614f0f565b9052610bd6565b816103a001516001600160401b038111156114a7576114a7613d4a565b6040519080825280602002602001820160405280156114da57816020015b60608152602001906001900390816114c55790505b509a50816103a001516001600160401b038111156114fa576114fa613d4a565b60405190808252806020026020018201604052801561152d57816020015b60608152602001906001900390816115185790505b509950816103a001516001600160401b0381111561154d5761154d613d4a565b60405190808252806020026020018201604052801561158057816020015b606081526020019060019003908161156b5790505b509850816103a001516001600160401b038111156115a0576115a0613d4a565b6040519080825280602002602001820160405280156115d957816020015b6115c6613d0d565b8152602001906001900390816115be5790505b509750816103c001516001600160401b038111156115f9576115f9613d4a565b604051908082528060200260200182016040528015611622578160200160208202803683370190505b509650816103e001516001600160401b0381111561164257611642613d4a565b60405190808252806020026020018201604052801561166b578160200160208202803683370190505b5095508161040001516001600160401b0381111561168b5761168b613d4a565b6040519080825280602002602001820160405280156116b4578160200160208202803683370190505b5094508161042001516001600160401b038111156116d4576116d4613d4a565b6040519080825280602002602001820160405280156116fd578160200160208202803683370190505b5093508161044001516001600160401b0381111561171d5761171d613d4a565b604051908082528060200260200182016040528015611746578160200160208202803683370190505b505f6103a084018190526103c084018190526103e0840181905261040084018190526104208401819052610440840181905261046084015292505b81602001518261046001511015612620576040805160c08101825260608082525f6020830181905292820183905281018290526080810182905260a0810191909152816001600160a01b031663c56ebcd6845f0151856104600151815181106117ec576117ec61489f565b60200260200101516040518263ffffffff1660e01b815260040161181291815260200190565b5f60405180830381865afa15801561182c573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526118539190810190614e48565b90508060400151156126085761186d8d82602001516131d7565b61014088015261012087015261010086015260e085015260c084018190525160a08401525f610160840181905261018084018190525b8360a00151811015612606578360e0015181815181106118c5576118c561489f565b60200260200101516001600160401b038111156118e4576118e4613d4a565b60405190808252806020026020018201604052801561190d578160200160208202803683370190505b506102a085015261010084015180518290811061192c5761192c61489f565b60200260200101516001600160401b0381111561194b5761194b613d4a565b604051908082528060200260200182016040528015611974578160200160208202803683370190505b506102c08501525f5b8460e0015182815181106119935761199361489f565b6020026020010151811015611a1757846101200151856101600151815181106119be576119be61489f565b6020026020010151856102a0015182815181106119dd576119dd61489f565b60200260200101906001600160a01b031690816001600160a01b03168152505084610160018051611a0d90614f0f565b905260010161197d565b505f5b8461010001518281518110611a3157611a3161489f565b6020026020010151811015611aa15784610140015185610180015181518110611a5c57611a5c61489f565b6020026020010151856102c001518281518110611a7b57611a7b61489f565b60200260200101818152505084610180018051611a9790614f0f565b9052600101611a1a565b5081602001516001600160a01b0316632d433b288f6040518263ffffffff1660e01b8152600401611ae191906001600160a01b0391909116815260200190565b5f60405180830381865afa158015611afb573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611b229190810190614fa1565b6102208801526102008701526101e08601526101a085018190525f61024086018190526102608601819052610280860181905290516101c08601526104808501525b836101c0015184610480015110156125fe575f846101c00151856101e0015151611b8e9190614b0b565b5f610340870181905261036087018190526103808701529050806001600160401b03811115611bbf57611bbf613d4a565b604051908082528060200260200182016040528015611be8578160200160208202803683370190505b506102e08601525f5b81811015611c8057856101e0015186610240015181518110611c1557611c1561489f565b6020026020010151866102e001518281518110611c3457611c3461489f565b60200260200101906001600160a01b031690816001600160a01b03168152505085610240018051611c6490614f0f565b905261034086018051611c7690614f0f565b9052600101611bf1565b50846101c0015185610200015151611c989190614b0b565b9050806001600160401b03811115611cb257611cb2613d4a565b604051908082528060200260200182016040528015611cdb578160200160208202803683370190505b506103008601525f5b81811015611d5f5785610200015186610260015181518110611d0857611d0861489f565b60200260200101518661030001518281518110611d2757611d2761489f565b60200260200101818152505085610260018051611d4390614f0f565b905261036086018051611d5590614f0f565b9052600101611ce4565b50846101c0015185610220015151611d779190614b0b565b9050806001600160401b03811115611d9157611d91613d4a565b604051908082528060200260200182016040528015611dba578160200160208202803683370190505b506103208601525f5b81811015611e465785610220015186610280015181518110611de757611de761489f565b60200260200101518661032001518281518110611e0657611e0661489f565b602002602001019060020b908160020b8152505085610280018051611e2a90614f0f565b905261038086018051611e3c90614f0f565b9052600101611dc3565b505f611ec98660c001518481518110611e6157611e6161489f565b6020026020010151855f0151886102a00151896102c001518a6102e001518b61030001518c61032001516040518060a00160405280600160ff1681526020015f60ff168152602001600160ff168152602001600160ff1681526020015f60ff16815250612c61565b604051637d474fa360e01b8152600481018290529091505f906001600160a01b03871690637d474fa390602401602060405180830381865afa158015611f11573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f3591906148be565b6001600160a01b0316036125e557856101a0015186610480015181518110611f5f57611f5f61489f565b60200260200101518f876103a0015181518110611f7e57611f7e61489f565b60200260200101819052508560c001518381518110611f9f57611f9f61489f565b60200260200101518e876103a0015181518110611fbe57611fbe61489f565b6020026020010181905250835f01518d876103a0015181518110611fe457611fe461489f565b6020026020010181905250856103c001518c876103a001518151811061200c5761200c61489f565b60200260200101515f600a81106120255761202561489f565b602002015260e08601518051849081106120415761204161489f565b6020026020010151866103c0015161205991906149b5565b8c876103a00151815181106120705761207061489f565b60200260200101516001600a811061208a5761208a61489f565b60200201526103e08601516103a08701518d518e919081106120ae576120ae61489f565b60200260200101516002600a81106120c8576120c861489f565b60200201526101008601518051849081106120e5576120e561489f565b6020026020010151866103e001516120fd91906149b5565b8c876103a00151815181106121145761211461489f565b60200260200101516003600a811061212e5761212e61489f565b60200201526104008601516103a08701518d518e919081106121525761215261489f565b60200260200101516004600a811061216c5761216c61489f565b602002015261034086015161040087015161218791906149b5565b8c876103a001518151811061219e5761219e61489f565b60200260200101516005600a81106121b8576121b861489f565b60200201526104208601516103a08701518d518e919081106121dc576121dc61489f565b60200260200101516006600a81106121f6576121f661489f565b602002015261036086015161042087015161221191906149b5565b8c876103a00151815181106122285761222861489f565b60200260200101516007600a81106122425761224261489f565b60200201526104408601516103a08701518d518e919081106122665761226661489f565b60200260200101516008600a81106122805761228061489f565b602002015261038086015161044087015161229b91906149b5565b8c876103a00151815181106122b2576122b261489f565b60200260200101516009600a81106122cc576122cc61489f565b60200201525f5b8660e0015184815181106122e9576122e961489f565b602002602001015181101561235957866102a00151818151811061230f5761230f61489f565b60200260200101518c82896103c0015161232991906149b5565b815181106123395761233961489f565b6001600160a01b03909216602092830291909101909101526001016122d3565b505f5b86610100015184815181106123735761237361489f565b60200260200101518110156123d657866102c0015181815181106123995761239961489f565b60200260200101518b82896103e001516123b391906149b5565b815181106123c3576123c361489f565b602090810291909101015260010161235c565b505f5b86610340015181101561244757866102e0015181815181106123fd576123fd61489f565b60200260200101518a8289610400015161241791906149b5565b815181106124275761242761489f565b6001600160a01b03909216602092830291909101909101526001016123d9565b505f5b8661036001518110156124ab57866103000151818151811061246e5761246e61489f565b6020026020010151898289610420015161248891906149b5565b815181106124985761249861489f565b602090810291909101015260010161244a565b505f5b8661038001518110156125175786610320015181815181106124d2576124d261489f565b602002602001015188828961044001516124ec91906149b5565b815181106124fc576124fc61489f565b60029290920b602092830291909101909101526001016124ae565b50856103a001805161252890614f0f565b905260e08601518051849081106125415761254161489f565b6020026020010151866103c00181815161255b91906149b5565b9052506101008601518051849081106125765761257661489f565b6020026020010151866103e00181815161259091906149b5565b905250610340860151610400870180516125ab9083906149b5565b905250610360860151610420870180516125c69083906149b5565b905250610380860151610440870180516125e19083906149b5565b9052505b5050836104800180516125f790614f0f565b9052611b64565b6001016118a3565b505b508161046001805161261990614f0f565b9052611781565b50509193959799909294969850565b5f8190505f816001600160a01b0316630146056d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612670573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061269491906148d9565b90505f826001600160a01b0316635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126f791906148be565b90505f855f015f8481526020019081526020015f206040518060a00160405290815f82018054612726906146d1565b80601f0160208091040260200160405190810160405280929190818152602001828054612752906146d1565b801561279d5780601f106127745761010080835404028352916020019161279d565b820191905f5260205f20905b81548152906001019060200180831161278057829003601f168201915b505050918352505060018201546001600160a01b03811660208084019190915260ff600160a01b8304811615156040850152600160a81b9092049091161515606080840191909152600290930154608090920191909152820151908201519192509061282457604051630301207f60e21b8152600481018590526024015b60405180910390fd5b806001600160a01b0316836001600160a01b031603612859576040516316c7522960e31b81526004810185905260240161281b565b846001600160a01b031663d55ec6976040518163ffffffff1660e01b81526004015f604051808303815f87803b158015612891575f80fd5b505af11580156128a3573d5f803e3d5ffd5b5050604080516001600160a01b03808b16825280881660208301528516918101919091527f74cd4f776fca6a39fc6f0983929e27ca9b19899c0c1827713393042bbe2afb16925060600190505b60405180910390a150505050505050565b5f8190505f816001600160a01b031663c29df70a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612942573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061296691906148d9565b5f81815260018601602090815260408083208151635c60da1b60e01b81529151949550936001600160a01b03871692635c60da1b92600480820193918290030181865afa1580156129b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129dd91906148be565b60018301549091506001600160a01b03811690600160a81b900460ff16612a1a57604051630301207f60e21b81526004810185905260240161281b565b806001600160a01b0316826001600160a01b031603612a4f576040516316c7522960e31b81526004810185905260240161281b565b846001600160a01b031663d55ec6976040518163ffffffff1660e01b81526004015f604051808303815f87803b158015612a87575f80fd5b505af1158015612a99573d5f803e3d5ffd5b5050604080516001600160a01b03808b16825280871660208301528516918101919091527f746871013d9225e5b11b13b9256515b47fa5378b085f1ba9b07b5f5112480ccf925060600190506128f0565b60608385604051602001612aff929190615046565b60408051601f1981840301815260208381019092525f9092528451908501209091507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47014612b6c578083604051602001612b5a929190615097565b60405160208183030381529060405290505b604080518082019091526009815268526577617264696e6760b81b6020918201528651908701207f9ebab07909aaa4cdae2d5e985d99720616df0dc6818db31d46ea1437e7afe57f01612c585780825f81518110612bcc57612bcc61489f565b60200260200101516001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa158015612c0e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612c3591908101906150d2565b604051602001612c46929190615103565b60405160208183030381529060405290505b95945050505050565b5f8089604051602001612c7491906146b6565b60408051601f198184030181529082905280516020918201209250612c9b918b91016146b6565b60408051808303601f1901815291905280516020909101208851845192909101915f919060ff16811115612cd05750835160ff165b80821015612d0a57898281518110612cea57612cea61489f565b60200260200101516001600160a01b031683019250816001019150612cd0565b508751602085015160ff16811115612d265750602084015160ff165b5f91505b80821015612d5b57888281518110612d4457612d4461489f565b602002602001015183019250816001019150612d2a565b508651604085015160ff16811115612d775750604084015160ff165b5f91505b80821015612db557878281518110612d9557612d9561489f565b60200260200101516001600160a01b031683019250816001019150612d7b565b508551606085015160ff16811115612dd15750606084015160ff165b5f91505b80821015612e0657868281518110612def57612def61489f565b602002602001015183019250816001019150612dd5565b508451608085015160ff16811115612e225750608084015160ff165b5f91505b80821015612ea3575f868381518110612e4157612e4161489f565b602002602001015160020b1215612e7657858281518110612e6457612e6461489f565b602002602001015160020b5f03612e94565b858281518110612e8857612e8861489f565b602002602001015160020b5b83019250816001019150612e26565b50909a9950505050505050505050565b5f80836001600160a01b03166354aa3d086040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ef1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f1591906148be565b83519091505f5b81811015612f6857826001600160a01b0316858281518110612f4057612f4061489f565b60200260200101516001600160a01b031603612f605792506130c3915050565b600101612f1c565b505f1992505f5f1990505f866001600160a01b0316632b3297f96040518163ffffffff1660e01b8152600401602060405180830381865afa158015612faf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fd391906148be565b90505f5b8381101561309c575f826001600160a01b0316636e8811028984815181106130015761300161489f565b6020026020010151886040518363ffffffff1660e01b815260040161303c9291906001600160a01b0392831681529116602082015260400190565b5f60405180830381865afa158015613056573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261307d9190810190615152565b50805190915084811015613092578094508297505b5050600101612fd7565b505f1985036130be576040516305fcedf360e01b815260040160405180910390fd5b505050505b92915050565b5f6130d48383613ab9565b9392505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526131429186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050613b05565b50505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526131998482613b6b565b613142576040516001600160a01b0384811660248301525f60448301526131cd91869182169063095ea7b390606401613110565b6131428482613b05565b606080606080606061320d6040518060a00160405280606081526020015f81526020015f81526020015f81526020015f81525090565b866001600160a01b031663fdff667c6040518163ffffffff1660e01b81526004015f60405180830381865afa158015613248573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261326f9190810190615259565b808252516080820152604080516360997e8560e01b815290515f916001600160a01b038b16916360997e859160048082019286929091908290030181865afa1580156132bd573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526132e4919081019061528a565b5080519091505f5b836080015181101561357c57734f76add676c04eca837130ceb58bc173de8799de6321a49642855f015183815181106133275761332761489f565b60200260200101516040518060400160405280600b81526020016a436f6d706f756e64696e6760a81b8152506040518363ffffffff1660e01b8152600401613370929190614850565b602060405180830381865af415801561338b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133af9190614884565b156133ca578360200180516133c390614f0f565b9052613574565b734f76add676c04eca837130ceb58bc173de8799de6321a49642855f015183815181106133f9576133f961489f565b602002602001015160405180604001604052806009815260200168526577617264696e6760b81b8152506040518363ffffffff1660e01b8152600401613440929190614850565b602060405180830381865af415801561345b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061347f9190614884565b806135425750734f76add676c04eca837130ceb58bc173de8799de6321a49642855f015183815181106134b4576134b461489f565b60200260200101516040518060400160405280601181526020017014995dd85c991a5b99c813585b9859d959607a1b8152506040518363ffffffff1660e01b8152600401613503929190614850565b602060405180830381865af415801561351e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135429190614884565b1561357457818460200181815161355991906149b5565b9052506040840180518391906135709083906149b5565b9052505b6001016132ec565b5082602001516001600160401b0381111561359957613599613d4a565b6040519080825280602002602001820160405280156135cc57816020015b60608152602001906001900390816135b75790505b50975082602001516001600160401b038111156135eb576135eb613d4a565b604051908082528060200260200182016040528015613614578160200160208202803683370190505b50965082602001516001600160401b0381111561363357613633613d4a565b60405190808252806020026020018201604052801561365c578160200160208202803683370190505b50955082604001516001600160401b0381111561367b5761367b613d4a565b6040519080825280602002602001820160405280156136a4578160200160208202803683370190505b50945082606001516001600160401b038111156136c3576136c3613d4a565b6040519080825280602002602001820160405280156136ec578160200160208202803683370190505b5093506136f7613d2c565b5f5b8460800151811015613aaa57734f76add676c04eca837130ceb58bc173de8799de6321a49642865f015183815181106137345761373461489f565b60200260200101516040518060400160405280600b81526020016a436f6d706f756e64696e6760a81b8152506040518363ffffffff1660e01b815260040161377d929190614850565b602060405180830381865af4158015613798573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906137bc9190614884565b156138245784518051829081106137d5576137d561489f565b60200260200101518a835f600381106137f0576137f061489f565b6020020151815181106138055761380561489f565b60209081029190910101528151829061381d90614f0f565b9052613aa2565b734f76add676c04eca837130ceb58bc173de8799de6321a49642865f015183815181106138535761385361489f565b602002602001015160405180604001604052806009815260200168526577617264696e6760b81b8152506040518363ffffffff1660e01b815260040161389a929190614850565b602060405180830381865af41580156138b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906138d99190614884565b8061399c5750734f76add676c04eca837130ceb58bc173de8799de6321a49642865f0151838151811061390e5761390e61489f565b60200260200101516040518060400160405280601181526020017014995dd85c991a5b99c813585b9859d959607a1b8152506040518363ffffffff1660e01b815260040161395d929190614850565b602060405180830381865af4158015613978573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061399c9190614884565b15613aa2575f5b83811015613aa05785518051839081106139bf576139bf61489f565b60200260200101518b845f600381106139da576139da61489f565b6020020151815181106139ef576139ef61489f565b6020026020010181905250848181518110613a0c57613a0c61489f565b60200260200101518884600160038110613a2857613a2861489f565b602002015181518110613a3d57613a3d61489f565b6001600160a01b03929092166020928302919091019091015282518a516001918c918110613a6d57613a6d61489f565b602090810291909101015282518390613a8590614f0f565b9052602083018051613a9690614f0f565b90526001016139a3565b505b6001016136f9565b50505050509295509295909350565b5f818152600183016020526040812054613afe57508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556130c3565b505f6130c3565b5f613b196001600160a01b03841683613c08565b905080515f14158015613b3d575080806020019051810190613b3b9190614884565b155b15613b6657604051635274afe760e01b81526001600160a01b038416600482015260240161281b565b505050565b5f805f846001600160a01b031684604051613b8691906146b6565b5f604051808303815f865af19150503d805f8114613bbf576040519150601f19603f3d011682016040523d82523d5f602084013e613bc4565b606091505b5091509150818015613bee575080511580613bee575080806020019051810190613bee9190614884565b8015612c585750505050506001600160a01b03163b151590565b60606130d483835f845f80856001600160a01b03168486604051613c2c91906146b6565b5f6040518083038185875af1925050503d805f8114613c66576040519150601f19603f3d011682016040523d82523d5f602084013e613c6b565b606091505b5091509150613c7b868383613c85565b9695505050505050565b606082613c9a57613c9582613ce1565b6130d4565b8151158015613cb157506001600160a01b0384163b155b15613cda57604051639996b31560e01b81526001600160a01b038516600482015260240161281b565b50806130d4565b805115613cf15780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b50565b604051806101400160405280600a906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b634e487b7160e01b5f52604160045260245ffd5b60405160a081016001600160401b0381118282101715613d8057613d80613d4a565b60405290565b60405160e081016001600160401b0381118282101715613d8057613d80613d4a565b60405160c081016001600160401b0381118282101715613d8057613d80613d4a565b604051608081016001600160401b0381118282101715613d8057613d80613d4a565b604051601f8201601f191681016001600160401b0381118282101715613e1457613e14613d4a565b604052919050565b5f6001600160401b03821115613e3457613e34613d4a565b50601f01601f191660200190565b5f82601f830112613e51575f80fd5b8135613e64613e5f82613e1c565b613dec565b818152846020838601011115613e78575f80fd5b816020850160208301375f918101602001919091529392505050565b6001600160a01b0381168114613d0a575f80fd5b8015158114613d0a575f80fd5b5f8060408385031215613ec6575f80fd5b8235915060208301356001600160401b0380821115613ee3575f80fd5b9084019060a08287031215613ef6575f80fd5b613efe613d5e565b823582811115613f0c575f80fd5b613f1888828601613e42565b82525060208301359150613f2b82613e94565b81602082015260408301359150613f4182613ea8565b81604082015260608301359150613f5782613ea8565b816060820152608083013560808201528093505050509250929050565b5f6001600160401b03821115613f8c57613f8c613d4a565b5060051b60200190565b5f82601f830112613fa5575f80fd5b81356020613fb5613e5f83613f74565b8083825260208201915060208460051b870101935086841115613fd6575f80fd5b602086015b84811015613ffb578035613fee81613e94565b8352918301918301613fdb565b509695505050505050565b5f82601f830112614015575f80fd5b81356020614025613e5f83613f74565b8083825260208201915060208460051b870101935086841115614046575f80fd5b602086015b84811015613ffb578035835291830191830161404b565b5f805f805f60a08688031215614076575f80fd5b853561408181613e94565b9450602086013561409181613e94565b935060408601356001600160401b03808211156140ac575f80fd5b6140b889838a01613e42565b945060608801359150808211156140cd575f80fd5b6140d989838a01613f96565b935060808801359150808211156140ee575f80fd5b506140fb88828901614006565b9150509295509295909350565b5f60208284031215614118575f80fd5b81356130d481613e94565b5f5b8381101561413d578181015183820152602001614125565b50505f910152565b5f815180845261415c816020860160208601614123565b601f01601f19169290920160200192915050565b5f8282518085526020808601955060208260051b840101602086015f5b848110156141bb57601f198684030189526141a9838351614145565b9884019892509083019060010161418d565b5090979650505050505050565b5f815180845260208085019450602084015f5b838110156142005781516001600160a01b0316875295820195908201906001016141db565b509495945050505050565b5f815180845260208085019450602084015f5b838110156142005781518752958201959082019060010161421e565b5f815180845260208085019450602084015f5b8381101561420057815160020b8752958201959082019060010161424d565b5f61012080835261427f8184018d614170565b9050602083820381850152614294828d614170565b915083820360408501526142a8828c614170565b84810360608601528a51808252828c019350908201905f5b81811015614301578451835f5b600a8110156142ea578251825291860191908601906001016142cd565b5050509383019361014092909201916001016142c0565b50508481036080860152614315818b6141c8565b9250505082810360a084015261432b818861420b565b905082810360c084015261433f81876141c8565b905082810360e0840152614353818661420b565b9050828103610100840152614368818561423a565b9c9b505050505050505050505050565b5f8060408385031215614389575f80fd5b82359150602083013561439b81613e94565b809150509250929050565b5f805f805f60a086880312156143ba575f80fd5b85356001600160401b03808211156143d0575f80fd5b6143dc89838a01613e42565b965060208801359150808211156143f1575f80fd5b6143fd89838a01613e42565b95506040880135915080821115614412575f80fd5b61441e89838a01613e42565b94506060880135915080821115614433575f80fd5b61443f89838a01613e42565b93506080880135915080821115614454575f80fd5b506140fb88828901613f96565b602081525f6130d46020830184614145565b8060020b8114613d0a575f80fd5b5f82601f830112614490575f80fd5b813560206144a0613e5f83613f74565b8083825260208201915060208460051b8701019350868411156144c1575f80fd5b602086015b84811015613ffb5780356144d981614473565b83529183019183016144c6565b60ff81168114613d0a575f80fd5b5f82601f830112614503575f80fd5b61450b613d5e565b8060a084018581111561451c575f80fd5b845b8181101561453f578035614531816144e6565b84526020938401930161451e565b509095945050505050565b5f805f805f805f80610180898b031215614562575f80fd5b88356001600160401b0380821115614578575f80fd5b6145848c838d01613e42565b995060208b0135915080821115614599575f80fd5b6145a58c838d01613e42565b985060408b01359150808211156145ba575f80fd5b6145c68c838d01613f96565b975060608b01359150808211156145db575f80fd5b6145e78c838d01614006565b965060808b01359150808211156145fc575f80fd5b6146088c838d01613f96565b955060a08b013591508082111561461d575f80fd5b6146298c838d01614006565b945060c08b013591508082111561463e575f80fd5b5061464b8b828c01614481565b92505061465b8a60e08b016144f4565b90509295985092959890939650565b5f806040838503121561467b575f80fd5b823561468681613e94565b915060208301356001600160401b038111156146a0575f80fd5b6146ac85828601613f96565b9150509250929050565b5f82516146c7818460208701614123565b9190910192915050565b600181811c908216806146e557607f821691505b60208210810361470357634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115613b6657805f5260205f20601f840160051c8101602085101561472e5750805b601f840160051c820191505b8181101561474d575f815560010161473a565b5050505050565b81516001600160401b0381111561476d5761476d613d4a565b6147818161477b84546146d1565b84614709565b602080601f8311600181146147b4575f841561479d5750858301515b5f19600386901b1c1916600185901b178555610976565b5f85815260208120601f198616915b828110156147e2578886015182559484019460019091019084016147c3565b50858210156147ff57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b60a081525f61482160a0830188614145565b6001600160a01b0396909616602083015250921515604084015290151560608301521515608090910152919050565b604081525f6148626040830185614145565b8281036020840152612c588185614145565b805161487f81613ea8565b919050565b5f60208284031215614894575f80fd5b81516130d481613ea8565b634e487b7160e01b5f52603260045260245ffd5b805161487f81613e94565b5f602082840312156148ce575f80fd5b81516130d481613e94565b5f602082840312156148e9575f80fd5b5051919050565b5f82601f8301126148ff575f80fd5b8151602061490f613e5f83613f74565b8083825260208201915060208460051b870101935086841115614930575f80fd5b602086015b84811015613ffb57805161494881613e94565b8352918301918301614935565b5f60208284031215614965575f80fd5b81516001600160401b0381111561497a575f80fd5b614986848285016148f0565b949350505050565b634e487b7160e01b5f52601160045260245ffd5b818103818111156130c3576130c361498e565b808201808211156130c3576130c361498e565b5f80604083850312156149d9575f80fd5b82519150602083015161439b81613ea8565b5f602082840312156149fb575f80fd5b81516130d4816144e6565b600181815b80851115614a4057815f1904821115614a2657614a2661498e565b80851615614a3357918102915b93841c9390800290614a0b565b509250929050565b5f82614a56575060016130c3565b81614a6257505f6130c3565b8160018114614a785760028114614a8257614a9e565b60019150506130c3565b60ff841115614a9357614a9361498e565b50506001821b6130c3565b5060208310610133831016604e8410600b8410161715614ac1575081810a6130c3565b614acb8383614a06565b805f1904821115614ade57614ade61498e565b029392505050565b5f6130d460ff841683614a48565b80820281158282048414176130c3576130c361498e565b5f82614b2557634e487b7160e01b5f52601260045260245ffd5b500490565b5f6020808385031215614b3b575f80fd5b82516001600160401b03811115614b50575f80fd5b8301601f81018513614b60575f80fd5b8051614b6e613e5f82613f74565b81815260059190911b82018301908381019087831115614b8c575f80fd5b928401925b82841015614baa57835182529284019290840190614b91565b979650505050505050565b5f82601f830112614bc4575f80fd5b8151614bd2613e5f82613e1c565b818152846020838601011115614be6575f80fd5b614986826020830160208701614123565b5f82601f830112614c06575f80fd5b81516020614c16613e5f83613f74565b8083825260208201915060208460051b870101935086841115614c37575f80fd5b602086015b84811015613ffb5780518352918301918301614c3c565b5f82601f830112614c62575f80fd5b81516020614c72613e5f83613f74565b8083825260208201915060208460051b870101935086841115614c93575f80fd5b602086015b84811015613ffb578051614cab81614473565b8352918301918301614c98565b5f6020808385031215614cc9575f80fd5b82516001600160401b0380821115614cdf575f80fd5b818501915085601f830112614cf2575f80fd5b8151614d00613e5f82613f74565b81815260059190911b83018401908481019088831115614d1e575f80fd5b8585015b83811015614e3b57805185811115614d38575f80fd5b860160e0818c03601f19011215614d4d575f80fd5b614d55613d86565b8882015181526040614d688184016148b3565b8a83015260608084015189811115614d7e575f80fd5b614d8c8f8d83880101614bb5565b8385015250608091508184015189811115614da5575f80fd5b614db38f8d838801016148f0565b82850152505060a08084015189811115614dcb575f80fd5b614dd98f8d838801016148f0565b838501525060c091508184015189811115614df2575f80fd5b614e008f8d83880101614bf7565b82850152505060e083015188811115614e17575f80fd5b614e258e8c83870101614c53565b9183019190915250845250918601918601614d22565b5098975050505050505050565b5f60208284031215614e58575f80fd5b81516001600160401b0380821115614e6e575f80fd5b9083019060c08286031215614e81575f80fd5b614e89613da8565b825182811115614e97575f80fd5b614ea387828601614bb5565b82525060208301519150614eb682613e94565b81602082015260408301519150614ecc82613ea8565b81604082015260608301519150614ee282613ea8565b816060820152614ef460808401614874565b608082015260a083015160a082015280935050505092915050565b5f60018201614f2057614f2061498e565b5060010190565b5f82601f830112614f36575f80fd5b81516020614f46613e5f83613f74565b82815260059290921b84018101918181019086841115614f64575f80fd5b8286015b84811015613ffb5780516001600160401b03811115614f85575f80fd5b614f938986838b0101614bb5565b845250918301918301614f68565b5f805f8060808587031215614fb4575f80fd5b84516001600160401b0380821115614fca575f80fd5b614fd688838901614f27565b95506020870151915080821115614feb575f80fd5b614ff7888389016148f0565b9450604087015191508082111561500c575f80fd5b61501888838901614bf7565b9350606087015191508082111561502d575f80fd5b5061503a87828801614c53565b91505092959194509250565b69029ba30b134b634ba3c960b51b81525f835161506a81600a850160208801614123565b600160fd1b600a91840191820152835161508b81600b840160208801614123565b01600b01949350505050565b5f83516150a8818460208801614123565b600160fd1b90830190815283516150c6816001840160208801614123565b01600101949350505050565b5f602082840312156150e2575f80fd5b81516001600160401b038111156150f7575f80fd5b61498684828501614bb5565b5f8351615114818460208801614123565b600160fd1b9083019081528351615132816001840160208801614123565b66081c995dd85c9960ca1b60019290910191820152600801949350505050565b5f806040808486031215615164575f80fd5b83516001600160401b038082111561517a575f80fd5b818601915086601f83011261518d575f80fd5b8151602061519d613e5f83613f74565b82815260079290921b8401810191818101908a8411156151bb575f80fd5b948201945b83861015615233576080868c0312156151d7575f80fd5b6151df613dca565b86516151ea81613e94565b8152868401516151f981613e94565b818501528688015161520a81613e94565b8189015260608781015161521d81613e94565b90820152825260809590950194908201906151c0565b9189015191975090945050508083111561524b575f80fd5b50506146ac85828601614bb5565b5f60208284031215615269575f80fd5b81516001600160401b0381111561527e575f80fd5b61498684828501614f27565b5f806040838503121561529b575f80fd5b82516001600160401b03808211156152b1575f80fd5b6152bd868387016148f0565b935060208501519150808211156152d2575f80fd5b506146ac85828601614bf756fea264697066735822122066e0519974f18a8866e479e1adf04d9ae5110a8f3cf4d34303208ef772abe59e64736f6c63430008170033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.