Address Details
contract
0xa5b6194de99e6e3f693c02950b26C3201c211849
- Contract Name
- DefaultStrategy
- Creator
- 0x5bc1c4–68a788 at 0x594fb7–43e251
- Balance
- 0 CELO ( )
- Locked CELO Balance
- 0.00 CELO
- Voting CELO Balance
- 0.00 CELO
- Pending Unlocked Gold
- 0.00 CELO
- Tokens
-
Fetching tokens...
- Transactions
- 0 Transactions
- Transfers
- 0 Transfers
- Gas Used
- Fetching gas used...
- Last Balance Update
- 17705458
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- DefaultStrategy
- Optimization enabled
- false
- Compiler version
- v0.8.11+commit.d7f03943
- EVM Version
- istanbul
- Verified at
- 2023-05-12T13:32:19.259646Z
contracts/DefaultStrategy.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.11; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "./common/UUPSOwnableUpgradeable.sol"; import "./common/linkedlists/AddressSortedLinkedList.sol"; import "./interfaces/IAccount.sol"; import "./interfaces/IGroupHealth.sol"; import "./interfaces/IManager.sol"; import "./interfaces/ISpecificGroupStrategy.sol"; import "./Managed.sol"; /** * @title DefaultStrategy is responsible for handling any deposit/withdrawal * for accounts without any specific strategy. */ contract DefaultStrategy is UUPSOwnableUpgradeable, Managed { using EnumerableSet for EnumerableSet.AddressSet; using AddressSortedLinkedList for SortedLinkedList.List; /** * @notice Holds a group's address and votes. * @param group The address of the group. * @param votes The votes assigned to the group. */ struct GroupWithVotes { address group; uint256 votes; } /** * @notice The set of currently active groups that will be voted for with * new deposits. */ SortedLinkedList.List private activeGroups; /** * @notice An instance of the GroupHealth contract for the StakedCelo protocol. */ IGroupHealth public groupHealth; /** * @notice An instance of the Account contract for the StakedCelo protocol. */ IAccount public account; /** * @notice An instance of the SpecificGroupStrategy for the StakedCelo protocol. */ ISpecificGroupStrategy public specificGroupStrategy; /** * @notice StCELO that was cast for default group strategy, * strategy => stCELO amount. */ mapping(address => uint256) public stCeloInGroup; /** * @notice Maximum number of groups to distribute votes to. */ uint256 public maxGroupsToDistributeTo; /** * @notice Maximum number of groups to withdraw from. */ uint256 public maxGroupsToWithdrawFrom; /** * @notice Total stCELO that was voted with on default strategy. */ uint256 public totalStCeloInStrategy; /** * @notice Loop limit while sorting active groups on chain. */ uint256 private sortingLoopLimit; /** * @notice Whether or not active groups are sorted. * If active groups are not sorted it is neccessary to call updateActiveGroupOrder. */ bool public sorted; /** * @notice Groups that need to be sorted. */ EnumerableSet.AddressSet private unsortedGroups; /** * @notice Emitted when a group is deactivated. * @param group The group's address. */ event GroupRemoved(address indexed group); /** * @notice Emitted when a new group is activated for voting. * @param group The group's address. */ event GroupActivated(address indexed group); /** * Emmited when sorted status of active groups was changed. * @param update The new value. */ event SortedFlagUpdated(bool update); /** * @notice Used when attempting to activate a group that is already active. * @param group The group's address. */ error GroupAlreadyAdded(address group); /** * @notice Used when a group does not meet the validator group health requirements. * @param group The group's address. */ error GroupNotEligible(address group); /** * @notice Used when attempting to deactivate a group that is not active. * @param group The group's address. */ error GroupNotActive(address group); /** * @notice Used when attempting to deactivate a healthy group using deactivateUnhealthyGroup(). * @param group The group's address. */ error HealthyGroup(address group); /** * @notice Used when attempting to deposit when there are no active groups * to vote for. */ error NoActiveGroups(); /** * @notice Used when atempting to distribute votes but validator group limit is reached. */ error NotAbleToDistributeVotes(); /** * @notice Used when attempting sort active groups when there are no unsorted group. */ error NotUnsortedGroup(); /** * @notice Used when rebalancing to a non-active group. * @param group The group's address. */ error InvalidToGroup(address group); /** * @notice Used when rebalancing from non-active group. * @param group The group's address. */ error InvalidFromGroup(address group); /** * @notice Used when rebalancing and `fromGroup` doesn't have any extra stCELO. * @param group The group's address. * @param actualCelo The actual stCELO value. * @param expectedCelo The expected stCELO value. */ error RebalanceNoExtraStCelo(address group, uint256 actualCelo, uint256 expectedCelo); /** * @notice Used when rebalancing and `toGroup` has enough stCELO. * @param group The group's address. * @param actualCelo The actual stCELO value. * @param expectedCelo The expected stCELO value. */ error RebalanceEnoughStCelo(address group, uint256 actualCelo, uint256 expectedCelo); /** * @notice Used when attempting to pass in address zero where not allowed. */ error AddressZeroNotAllowed(); /** * @notice Used when a `managerOrStrategy` function is called * by a non-manager or non-strategy. * @param caller `msg.sender` that called the function. */ error CallerNotManagerNorStrategy(address caller); /** * @notice Checks that only the manager or strategy contract can execute a function. */ modifier managerOrStrategy() { if (manager != msg.sender && address(specificGroupStrategy) != msg.sender) { revert CallerNotManagerNorStrategy(msg.sender); } _; } /** * @notice Empty constructor for proxy implementation, `initializer` modifer ensures the * implementation gets initialized. */ // solhint-disable-next-line no-empty-blocks constructor() initializer {} /** * @notice Initialize the contract with registry and owner. * @param _owner The address of the contract owner. * @param _manager The address of the Manager contract. */ function initialize(address _owner, address _manager) external initializer { _transferOwnership(_owner); __Managed_init(_manager); maxGroupsToDistributeTo = 8; maxGroupsToWithdrawFrom = 8; sortingLoopLimit = 10; sorted = true; emit SortedFlagUpdated(sorted); } /** * @notice Set this contract's dependencies in the StakedCelo system. * @param _account The address of the Account contract. * @param _groupHealth The address of the GroupHealth contract. * @param _specificGroupStrategy The address of the SpecificGroupStrategy contract. */ function setDependencies( address _account, address _groupHealth, address _specificGroupStrategy ) external onlyOwner { if ( _account == address(0) || _groupHealth == address(0) || _specificGroupStrategy == address(0) ) { revert AddressZeroNotAllowed(); } groupHealth = IGroupHealth(_groupHealth); specificGroupStrategy = ISpecificGroupStrategy(_specificGroupStrategy); account = IAccount(_account); } /** * @notice Set distribution/withdrawal algorithm parameters. * @param distributeTo Maximum number of groups that can be distributed to. * @param withdrawFrom Maximum number of groups that can be withdrawn from. * @param loopLimit The sorting loop limit while sorting active groups on chain. */ function setSortingParams( uint256 distributeTo, uint256 withdrawFrom, uint256 loopLimit ) external onlyOwner { maxGroupsToDistributeTo = distributeTo; maxGroupsToWithdrawFrom = withdrawFrom; sortingLoopLimit = loopLimit; } /** * @notice Distributes votes by computing the number of votes each active * group should receive. * @param celoAmount The amount of votes to distribute. * @param depositGroupToIgnore The group that will not be used for deposit. * @return finalGroups The groups that were chosen for distribution. * @return finalVotes The votes of chosen finalGroups. */ function generateDepositVoteDistribution(uint256 celoAmount, address depositGroupToIgnore) external managerOrStrategy returns (address[] memory finalGroups, uint256[] memory finalVotes) { return _generateDepositVoteDistribution(celoAmount, depositGroupToIgnore); } /** * @notice Updates group order of unsorted group. When there are no more unsorted groups * it will mark active groups as sorted. * @param group The group address. * @param lesserKey The key of the group less than the group to update. * @param greaterKey The key of the group greater than the group to update. */ function updateActiveGroupOrder( address group, address lesserKey, address greaterKey ) external { if (!unsortedGroups.contains(group)) { revert NotUnsortedGroup(); } activeGroups.update(group, stCeloInGroup[group], lesserKey, greaterKey); unsortedGroups.remove(group); if (unsortedGroups.length() == 0) { sorted = true; emit SortedFlagUpdated(sorted); } } /** * @notice Marks a group as votable for default strategy. * It is necessary to call `updateGroupHealth` in GroupHealth smart contract first. * @param group The address of the group to add to the set of votable * groups. * @param lesser The group receiving fewer votes (in default strategy) than `group`, * or 0 if `group` has the fewest votes of any validator group. * @param greater The group receiving more votes (in default strategy) than `group`, * or 0 if `group` has the most votes of any validator group. */ function activateGroup( address group, address lesser, address greater ) external onlyOwner { if (!groupHealth.isGroupValid(group)) { revert GroupNotEligible(group); } if (activeGroups.contains(group)) { revert GroupAlreadyAdded(group); } // For migration purposes between V1 and V2. It can be removed once migrated to V2. uint256 currentStCelo = 0; uint256 stCeloForWholeGroup = IManager(manager).toStakedCelo( account.getCeloForGroup(group) ); if (stCeloForWholeGroup != 0) { (uint256 specificGroupTotalStCelo, , ) = specificGroupStrategy.getStCeloInGroup(group); currentStCelo = stCeloForWholeGroup - Math.min(stCeloForWholeGroup, specificGroupTotalStCelo); updateGroupStCelo(group, currentStCelo, true); } activeGroups.insert(group, currentStCelo, lesser, greater); emit GroupActivated(group); } /** * @notice Rebalances CELO between groups that have an incorrect CELO-stCELO ratio. * `fromGroup` is required to have more CELO than it should and `toGroup` needs * to have less CELO than it should. * @param fromGroup The from group. * @param toGroup The to group. */ function rebalance(address fromGroup, address toGroup) external { if (!activeGroups.contains(fromGroup)) { revert InvalidFromGroup(fromGroup); } if (!activeGroups.contains(toGroup)) { revert InvalidToGroup(toGroup); } (uint256 expectedFromStCelo, uint256 actualFromStCelo) = getExpectedAndActualStCeloForGroup( fromGroup ); if (actualFromStCelo <= expectedFromStCelo) { // fromGroup needs to have more stCELO than it should revert RebalanceNoExtraStCelo(fromGroup, actualFromStCelo, expectedFromStCelo); } (uint256 expectedToStCelo, uint256 actualToStCelo) = getExpectedAndActualStCeloForGroup( toGroup ); if (actualToStCelo >= expectedToStCelo) { // toGroup needs to have less stCELO than it should revert RebalanceEnoughStCelo(toGroup, actualToStCelo, expectedToStCelo); } uint256 toMove = Math.min( actualFromStCelo - expectedFromStCelo, expectedToStCelo - actualToStCelo ); updateGroupStCelo(fromGroup, toMove, false); updateGroupStCelo(toGroup, toMove, true); trySort(fromGroup, stCeloInGroup[fromGroup], false); trySort(toGroup, stCeloInGroup[toGroup], true); } /** * @notice Distributes votes by computing the number of votes to be subtracted * from each active group. * @param celoAmount The amount of votes to subtract. * @return finalGroups The groups that were chosen for subtraction. * @return finalVotes The votes of chosen finalGroups. */ function generateWithdrawalVoteDistribution(uint256 celoAmount) external managerOrStrategy returns (address[] memory finalGroups, uint256[] memory finalVotes) { if (activeGroups.getNumElements() == 0) { revert NoActiveGroups(); } uint256 maxGroupCount = Math.min(maxGroupsToWithdrawFrom, activeGroups.getNumElements()); address[] memory groups = new address[](maxGroupCount); uint256[] memory votes = new uint256[](maxGroupCount); address votedGroup = activeGroups.getHead(); uint256 groupsIndex; while (groupsIndex < maxGroupCount && celoAmount != 0 && votedGroup != address(0)) { votes[groupsIndex] = Math.min( Math.min( account.getCeloForGroup(votedGroup), IManager(manager).toCelo(stCeloInGroup[votedGroup]) ), celoAmount ); groups[groupsIndex] = votedGroup; celoAmount -= votes[groupsIndex]; updateGroupStCelo( votedGroup, IManager(manager).toStakedCelo(votes[groupsIndex]), false ); trySort(votedGroup, stCeloInGroup[votedGroup], false); if (sorted) { votedGroup = activeGroups.getHead(); } else { (, votedGroup, ) = activeGroups.get(votedGroup); } groupsIndex++; } if (celoAmount != 0) { revert NotAbleToDistributeVotes(); } finalGroups = new address[](groupsIndex); finalVotes = new uint256[](groupsIndex); for (uint256 i = 0; i < groupsIndex; i++) { finalGroups[i] = groups[i]; finalVotes[i] = votes[i]; } } /** * @notice Deactivates group. * @param group The group to deactivated. */ function deactivateGroup(address group) external onlyOwner { _deactivateGroup(group); } /** * @notice Deactivates an unhealthy group. * @param group The group to deactivate if unhealthy. */ function deactivateUnhealthyGroup(address group) external { if (groupHealth.isGroupValid(group)) { revert HealthyGroup(group); } _deactivateGroup((group)); } /** * @notice Returns the number of active groups. * @return The number of active groups. */ function getNumberOfGroups() external view returns (uint256) { return activeGroups.getNumElements(); } /** * @notice Returns previous and next address of key. * @param group The group address. * @return previousAddress The previous address. * @return nextAddress The next address. */ function getGroupPreviousAndNext(address group) external view returns (address previousAddress, address nextAddress) { (, previousAddress, nextAddress) = activeGroups.get(group); } /** * @notice Returns head and previous address of head. * @return head The address of the sorted group with most votes. * @return previousAddress The previous address from head. */ function getGroupsHead() external view returns (address head, address previousAddress) { head = activeGroups.getHead(); (, previousAddress, ) = activeGroups.get(head); } /** * @notice Returns tail and next address of tail. * @return tail The address of the sorted group with least votes. * @return nextAddress The next address after tail. */ function getGroupsTail() external view returns (address tail, address nextAddress) { tail = activeGroups.getTail(); (, , nextAddress) = activeGroups.get(tail); } /** * @notice Returns whether active groups contain group. * @return Whether or not the given group is active. */ function isActive(address group) external view returns (bool) { return activeGroups.contains(group); } /** * @notice Returns the number of unsorted groups. * @return The number of unsorted groups. */ function getNumberOfUnsortedGroups() external view returns (uint256) { return unsortedGroups.length(); } /** * @notice Returns the unsorted group at index. * @param index The index to look up. * @return The group. */ function getUnsortedGroupAt(uint256 index) external view returns (address) { return unsortedGroups.at(index); } /** * @notice Returns the storage, major, minor, and patch version of the contract. * @return Storage version of the contract. * @return Major version of the contract. * @return Minor version of the contract. * @return Patch version of the contract. */ function getVersionNumber() external pure returns ( uint256, uint256, uint256, uint256 ) { return (1, 1, 0, 0); } /** * @notice Returns expected stCELO and actual stCELO for group. * @param group The group. * @return expectedStCelo The amount of stCELO that group should have. * (The total amount of stCELO in the default strategy divided by the number of active groups.) * @return actualStCelo The amount of stCELO which is currently * assigned to group in the strategy. */ function getExpectedAndActualStCeloForGroup(address group) public view returns (uint256 expectedStCelo, uint256 actualStCelo) { address head = activeGroups.getHead(); uint256 numberOfActiveGroups = activeGroups.getNumElements(); expectedStCelo = totalStCeloInStrategy / numberOfActiveGroups; if (group == head) { uint256 divisionResidue = totalStCeloInStrategy - (expectedStCelo * numberOfActiveGroups); expectedStCelo += divisionResidue; } actualStCelo = stCeloInGroup[group]; } /** * @notice Adds/substracts value to totals of group and * total stCELO in default strategy. * @param group The validator group that we are updating. * @param stCeloAmount The amount of stCELO. * @param add Whether to add or substract. */ function updateGroupStCelo( address group, uint256 stCeloAmount, bool add ) internal { if (add) { stCeloInGroup[group] += stCeloAmount; totalStCeloInStrategy += stCeloAmount; } else { stCeloInGroup[group] -= stCeloAmount; totalStCeloInStrategy -= stCeloAmount; } } /** * @notice Deactivates group. * @param group The group to deactivated. */ function _deactivateGroup(address group) private { if (!activeGroups.contains(group)) { revert GroupNotActive(group); } activeGroups.remove(group); unsortedGroups.remove(group); uint256 groupTotalStCeloVotes = stCeloInGroup[group]; if (groupTotalStCeloVotes > 0) { updateGroupStCelo(group, groupTotalStCeloVotes, false); address[] memory fromGroups = new address[](1); uint256[] memory fromVotes = new uint256[](1); fromGroups[0] = group; fromVotes[0] = IManager(manager).toCelo(groupTotalStCeloVotes); ( address[] memory toGroups, uint256[] memory toVotes ) = _generateDepositVoteDistribution( IManager(manager).toCelo(groupTotalStCeloVotes), address(0) ); IManager(manager).scheduleTransferWithinStrategy( fromGroups, toGroups, fromVotes, toVotes ); } emit GroupRemoved(group); } /** * @notice Distributes votes by computing the number of votes each active * group should receive. * @param celoAmount The amount of votes to distribute. * @param depositGroupToIgnore The group that will not be used for deposit. * @return finalGroups The groups that were chosen for distribution. * @return finalVotes The votes of chosen finalGroups. */ function _generateDepositVoteDistribution(uint256 celoAmount, address depositGroupToIgnore) private returns (address[] memory finalGroups, uint256[] memory finalVotes) { if (activeGroups.getNumElements() == 0) { revert NoActiveGroups(); } uint256 maxGroupCount = Math.min(maxGroupsToDistributeTo, activeGroups.getNumElements()); address[] memory groups = new address[](maxGroupCount); uint256[] memory votes = new uint256[](maxGroupCount); address votedGroup = activeGroups.getTail(); uint256 groupsIndex; while (groupsIndex < maxGroupCount && celoAmount != 0 && votedGroup != address(0)) { uint256 receivableVotes = IManager(manager).getReceivableVotesForGroup(votedGroup); if (votedGroup == depositGroupToIgnore || receivableVotes == 0) { (, , votedGroup) = activeGroups.get(votedGroup); continue; } votes[groupsIndex] = Math.min(receivableVotes, celoAmount); groups[groupsIndex] = votedGroup; celoAmount -= votes[groupsIndex]; updateGroupStCelo(votedGroup, IManager(manager).toStakedCelo(votes[groupsIndex]), true); trySort(votedGroup, stCeloInGroup[votedGroup], true); if (sorted) { votedGroup = activeGroups.getTail(); } else { (, , votedGroup) = activeGroups.get(votedGroup); } groupsIndex++; } if (celoAmount != 0) { revert NotAbleToDistributeVotes(); } finalGroups = new address[](groupsIndex); finalVotes = new uint256[](groupsIndex); for (uint256 i = 0; i < groupsIndex; i++) { finalGroups[i] = groups[i]; finalVotes[i] = votes[i]; } } /** * Try to sort group in active groups based on new value. * @param group The group address. * @param newValue The new value of group. * @param valueIncreased Whether value increased/decreased compared to original value. */ function trySort( address group, uint256 newValue, bool valueIncreased ) private { if (unsortedGroups.contains(group)) { return; } (address lesserKey, address greaterKey) = valueIncreased ? activeGroups.getLesserAndGreaterOfAddressThatIncreasedValue( group, newValue, sortingLoopLimit ) : activeGroups.getLesserAndGreaterOfAddressThatDecreasedValue( group, newValue, sortingLoopLimit ); if (lesserKey != greaterKey || activeGroups.getNumElements() == 1) { activeGroups.update(group, newValue, lesserKey, greaterKey); } else { if (sorted) { sorted = false; } unsortedGroups.add(group); } } }
/_openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967Upgrade { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallSecure( address newImplementation, bytes memory data, bool forceCall ) internal { address oldImplementation = _getImplementation(); // Initial upgrade and setup call _setImplementation(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } // Perform rollback test if not already in progress StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT); if (!rollbackTesting.value) { // Trigger rollback using upgradeTo from the new implementation rollbackTesting.value = true; Address.functionDelegateCall( newImplementation, abi.encodeWithSignature("upgradeTo(address)", oldImplementation) ); rollbackTesting.value = false; // Check rollback was effective require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades"); // Finally reset to the new implementation and log the upgrade _upgradeTo(newImplementation); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } }
/_openzeppelin/contracts/proxy/beacon/IBeacon.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
/_openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.0; import "../ERC1967/ERC1967Upgrade.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is ERC1967Upgrade { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeTo(address newImplementation) external virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallSecure(newImplementation, new bytes(0), false); } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallSecure(newImplementation, data, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; }
/_openzeppelin/contracts/utils/Address.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Address.sol) pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
/_openzeppelin/contracts/utils/StorageSlot.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly { r.slot := slot } } }
/_openzeppelin/contracts/utils/math/Math.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @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 up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a / b + (a % b == 0 ? 0 : 1); } }
/_openzeppelin/contracts/utils/structs/EnumerableSet.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol) pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { 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) { return _values(set._inner); } // 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; 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 on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev 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; assembly { result := store } return result; } }
/_openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
/_openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.0; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() initializer {} * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { // If the contract is initializing we ignore whether _initialized is set in order to support multiple // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the // contract may have been reentered. require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} modifier, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } }
/_openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
/_openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
/contracts/Managed.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.11; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /** * @title Used via inheritance to grant special access control to the Manager * contract. */ abstract contract Managed is Initializable, OwnableUpgradeable { address public manager; /** * @notice Emitted when the manager is initially set or later modified. * @param manager The new managing account address. */ event ManagerSet(address indexed manager); /** * @notice Used when an `onlyManager` function is called by a non-manager. * @param caller `msg.sender` that called the function. */ error CallerNotManager(address caller); /** * @notice Used when a passed address is address(0). */ error NullAddress(); /** * @dev Throws if called by any account other than the manager. */ modifier onlyManager() { if (manager != msg.sender) { revert CallerNotManager(msg.sender); } _; } /** * @notice Sets the manager address. * @param _manager The new manager address. */ function setManager(address _manager) external onlyOwner { _setManager(_manager); } /** * @dev Initializes the contract in an upgradable context. * @param _manager The initial managing address. */ // solhint-disable-next-line func-name-mixedcase function __Managed_init(address _manager) internal onlyInitializing { _setManager(_manager); } /** * @notice Sets the manager address. * @param _manager The new manager address. */ function _setManager(address _manager) internal { if (_manager == address(0)) { revert NullAddress(); } manager = _manager; emit ManagerSet(_manager); } }
/contracts/common/UUPSOwnableUpgradeable.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.11; import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; /** * @title A contract that links UUPSUUpgradeable with OwanbleUpgradeable to gate upgrades. */ abstract contract UUPSOwnableUpgradeable is UUPSUpgradeable, OwnableUpgradeable { /** * @notice Guard method for UUPS (Universal Upgradable Proxy Standard) * See: https://docs.openzeppelin.com/contracts/4.x/api/proxy#transparent-vs-uups * @dev This methods overrides the virtual one in UUPSUpgradeable and * adds the onlyOwner modifer. */ // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address) internal override onlyOwner {} }
/contracts/common/linkedlists/AddressSortedLinkedList.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.11; import "@openzeppelin/contracts/utils/math/Math.sol"; import "./SortedLinkedList.sol"; /** * @title Maintains a sorted list of unsigned ints keyed by address. */ library AddressSortedLinkedList { using SortedLinkedList for SortedLinkedList.List; /** * @notice Inserts an element into a doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to insert. * @param value The element value. * @param lesserKey The key of the element less than the element to insert. * @param greaterKey The key of the element greater than the element to insert. */ function insert( SortedLinkedList.List storage list, address key, uint256 value, address lesserKey, address greaterKey ) public { list.insert(toBytes(key), value, toBytes(lesserKey), toBytes(greaterKey)); } /** * @notice Removes an element from the doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to remove. */ function remove(SortedLinkedList.List storage list, address key) public { list.remove(toBytes(key)); } /** * @notice Updates an element in the list. * @param list A storage pointer to the underlying list. * @param key The element key. * @param value The element value. * @param lesserKey The key of the element will be just left of `key` after the update. * @param greaterKey The key of the element will be just right of `key` after the update. * @dev Note that only one of "lesserKey" or "greaterKey" needs to be correct to reduce friction. */ function update( SortedLinkedList.List storage list, address key, uint256 value, address lesserKey, address greaterKey ) public { list.update(toBytes(key), value, toBytes(lesserKey), toBytes(greaterKey)); } /** * @notice Returns whether or not a particular key is present in the sorted list. * @param list A storage pointer to the underlying list. * @param key The element key. * @return Whether or not the key is in the sorted list. */ function contains(SortedLinkedList.List storage list, address key) public view returns (bool) { return list.contains(toBytes(key)); } /** * @notice Returns the value for a particular key in the sorted list. * @param list A storage pointer to the underlying list. * @param key The element key. * @return The element value. */ function getValue(SortedLinkedList.List storage list, address key) public view returns (uint256) { return list.getValue(toBytes(key)); } /** * @notice Gets all elements from the doubly linked list. * @return Array of all keys in the list. * @return Values corresponding to keys, which will be ordered largest to smallest. */ function getElements(SortedLinkedList.List storage list) public view returns (address[] memory, uint256[] memory) { bytes32[] memory byteKeys = list.getKeys(); address[] memory keys = new address[](byteKeys.length); uint256[] memory values = new uint256[](byteKeys.length); for (uint256 i = 0; i < byteKeys.length; i = i + 1) { keys[i] = toAddress(byteKeys[i]); values[i] = list.values[byteKeys[i]]; } return (keys, values); } /** * @notice Returns the minimum of `max` and the number of elements in the list > threshold. * @param list A storage pointer to the underlying list. * @param threshold The number that the element must exceed to be included. * @param max The maximum number returned by this function. * @return The minimum of `max` and the number of elements in the list > threshold. */ function numElementsGreaterThan( SortedLinkedList.List storage list, uint256 threshold, uint256 max ) public view returns (uint256) { uint256 revisedMax = Math.min(max, list.list.numElements); bytes32 key = list.list.head; for (uint256 i = 0; i < revisedMax; i = i + 1) { if (list.getValue(key) < threshold) { return i; } key = list.list.elements[key].previousKey; } return revisedMax; } /** * @notice Returns the N greatest elements of the list. * @param list A storage pointer to the underlying list. * @param n The number of elements to return. * @return The keys of the greatest elements. */ function headN(SortedLinkedList.List storage list, uint256 n) public view returns (address[] memory) { bytes32[] memory byteKeys = list.headN(n); address[] memory keys = new address[](n); for (uint256 i = 0; i < n; i = i + 1) { keys[i] = toAddress(byteKeys[i]); } return keys; } /** * @notice Gets all element keys from the doubly linked list. * @param list A storage pointer to the underlying list. * @return All element keys from head to tail. */ function getKeys(SortedLinkedList.List storage list) public view returns (address[] memory) { return headN(list, list.list.numElements); } /** * @notice Returns the number of elements in the list. * @param list A storage pointer to the underlying list. * @return The number of elements in the list. */ function getNumElements(SortedLinkedList.List storage list) public view returns (uint256) { return list.list.numElements; } /** * @notice Returns the key of the first element in the list. * @param list A storage pointer to the underlying list. * @return The key of the first element in the list. */ function getHead(SortedLinkedList.List storage list) public view returns (address) { return toAddress(list.list.head); } /** * @notice Returns the key of the last element in the list. * @param list A storage pointer to the underlying list. * @return The key of the last element in the list. */ function getTail(SortedLinkedList.List storage list) public view returns (address) { return toAddress(list.list.tail); } /** * @notice Gets lesser and greater for address that has increased it's value. * @param list A storage pointer to the underlying list. * @param group The original address. * @param newValue New value that has to be bigger or equal than the previous one. * @param loopLimit The max limit of loops that will be executed. */ function getLesserAndGreaterOfAddressThatIncreasedValue( SortedLinkedList.List storage list, address group, uint256 newValue, uint256 loopLimit ) public view returns (address previous, address next) { (, previous, next) = get(list, group); while (next != address(0) && loopLimit != 0 && newValue > getValue(list, next)) { previous = next; (, , next) = get(list, previous); loopLimit--; } if (loopLimit == 0) { return (address(0), address(0)); } } /** * @notice Gets lesser and greater for address that has decreased it's value. * @param list A storage pointer to the underlying list. * @param group The original address. * @param newValue New value that has to be smaller or equal than the previous one. * @param loopLimit The max limit of loops that will be executed. */ function getLesserAndGreaterOfAddressThatDecreasedValue( SortedLinkedList.List storage list, address group, uint256 newValue, uint256 loopLimit ) public view returns (address previous, address next) { (, previous, next) = get(list, group); while (previous != address(0) && loopLimit != 0 && newValue < getValue(list, previous)) { next = previous; (, previous, ) = get(list, next); loopLimit--; } if (loopLimit == 0) { return (address(0), address(0)); } } function toBytes(address a) public pure returns (bytes32) { return bytes32(uint256(uint160(a)) << 96); } function toAddress(bytes32 b) public pure returns (address) { return address(uint160(uint256(b) >> 96)); } /** * @notice Returns Element based on key. * @param list A storage pointer to the underlying list. * @param key The element key. * @return exists Whether or not the key exists. * @return previousKey Previous key. * @return nextKey Next key. */ function get(SortedLinkedList.List storage list, address key) internal view returns (bool exists, address previousKey, address nextKey) { LinkedList.Element memory element = list.get(toBytes(key)); exists = element.exists; if (element.exists) { previousKey = toAddress(element.previousKey); nextKey = toAddress(element.nextKey); } } }
/contracts/common/linkedlists/LinkedList.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.11; /** * @title Maintains a doubly linked list keyed by bytes32. * @dev Following the `next` pointers will lead you to the head, rather than the tail. */ library LinkedList { struct Element { bytes32 previousKey; bytes32 nextKey; bool exists; } struct List { bytes32 head; bytes32 tail; uint256 numElements; mapping(bytes32 => Element) elements; } /** * @notice Inserts an element into a doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to insert. * @param previousKey The key of the element that comes before the element to insert. * @param nextKey The key of the element that comes after the element to insert. */ function insert(List storage list, bytes32 key, bytes32 previousKey, bytes32 nextKey) internal { require(key != bytes32(0), "Key must be defined"); require(!contains(list, key), "Can't insert an existing element"); require( previousKey != key && nextKey != key, "Key cannot be the same as previousKey or nextKey" ); Element storage element = list.elements[key]; element.exists = true; if (list.numElements == 0) { list.tail = key; list.head = key; } else { require( previousKey != bytes32(0) || nextKey != bytes32(0), "Either previousKey or nextKey must be defined" ); element.previousKey = previousKey; element.nextKey = nextKey; if (previousKey != bytes32(0)) { require( contains(list, previousKey), "If previousKey is defined, it must exist in the list" ); Element storage previousElement = list.elements[previousKey]; require(previousElement.nextKey == nextKey, "previousKey must be adjacent to nextKey"); previousElement.nextKey = key; } else { list.tail = key; } if (nextKey != bytes32(0)) { require(contains(list, nextKey), "If nextKey is defined, it must exist in the list"); Element storage nextElement = list.elements[nextKey]; require(nextElement.previousKey == previousKey, "previousKey must be adjacent to nextKey"); nextElement.previousKey = key; } else { list.head = key; } } list.numElements = list.numElements + 1; } /** * @notice Inserts an element at the tail of the doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to insert. */ function push(List storage list, bytes32 key) internal { insert(list, key, bytes32(0), list.tail); } /** * @notice Removes an element from the doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to remove. */ function remove(List storage list, bytes32 key) internal { Element storage element = list.elements[key]; require(key != bytes32(0) && contains(list, key), "key not in list"); if (element.previousKey != bytes32(0)) { Element storage previousElement = list.elements[element.previousKey]; previousElement.nextKey = element.nextKey; } else { list.tail = element.nextKey; } if (element.nextKey != bytes32(0)) { Element storage nextElement = list.elements[element.nextKey]; nextElement.previousKey = element.previousKey; } else { list.head = element.previousKey; } delete list.elements[key]; list.numElements = list.numElements - 1; } /** * @notice Updates an element in the list. * @param list A storage pointer to the underlying list. * @param key The element key. * @param previousKey The key of the element that comes before the updated element. * @param nextKey The key of the element that comes after the updated element. */ function update(List storage list, bytes32 key, bytes32 previousKey, bytes32 nextKey) internal { require( key != bytes32(0) && key != previousKey && key != nextKey && contains(list, key), "key on in list" ); remove(list, key); insert(list, key, previousKey, nextKey); } /** * @notice Returns whether or not a particular key is present in the sorted list. * @param list A storage pointer to the underlying list. * @param key The element key. * @return Whether or not the key is in the sorted list. */ function contains(List storage list, bytes32 key) internal view returns (bool) { return list.elements[key].exists; } /** * @notice Returns Element based on key. * @param list A storage pointer to the underlying list. * @param key The element key. * @return Whether or not the key is in the sorted list. */ function get(List storage list, bytes32 key) internal view returns (Element memory) { return list.elements[key]; } /** * @notice Returns the keys of the N elements at the head of the list. * @param list A storage pointer to the underlying list. * @param n The number of elements to return. * @return The keys of the N elements at the head of the list. * @dev Reverts if n is greater than the number of elements in the list. */ function headN(List storage list, uint256 n) internal view returns (bytes32[] memory) { require(n <= list.numElements, "not enough elements"); bytes32[] memory keys = new bytes32[](n); bytes32 key = list.head; for (uint256 i = 0; i < n; i = i + 1) { keys[i] = key; key = list.elements[key].previousKey; } return keys; } /** * @notice Gets all element keys from the doubly linked list. * @param list A storage pointer to the underlying list. * @return All element keys from head to tail. */ function getKeys(List storage list) internal view returns (bytes32[] memory) { return headN(list, list.numElements); } }
/contracts/common/linkedlists/SortedLinkedList.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.11; import "./LinkedList.sol"; /** * @title Maintains a sorted list of unsigned ints keyed by bytes32. */ library SortedLinkedList { using LinkedList for LinkedList.List; struct List { LinkedList.List list; mapping(bytes32 => uint256) values; } /** * @notice Inserts an element into a doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to insert. * @param value The element value. * @param lesserKey The key of the element less than the element to insert. * @param greaterKey The key of the element greater than the element to insert. */ function insert( List storage list, bytes32 key, uint256 value, bytes32 lesserKey, bytes32 greaterKey ) internal { require( key != bytes32(0) && key != lesserKey && key != greaterKey && !contains(list, key), "invalid key" ); require( (lesserKey != bytes32(0) || greaterKey != bytes32(0)) || list.list.numElements == 0, "greater and lesser key zero" ); require(contains(list, lesserKey) || lesserKey == bytes32(0), "invalid lesser key"); require(contains(list, greaterKey) || greaterKey == bytes32(0), "invalid greater key"); (lesserKey, greaterKey) = getLesserAndGreater(list, value, lesserKey, greaterKey); list.list.insert(key, lesserKey, greaterKey); list.values[key] = value; } /** * @notice Removes an element from the doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to remove. */ function remove(List storage list, bytes32 key) internal { list.list.remove(key); list.values[key] = 0; } /** * @notice Updates an element in the list. * @param list A storage pointer to the underlying list. * @param key The element key. * @param value The element value. * @param lesserKey The key of the element will be just left of `key` after the update. * @param greaterKey The key of the element will be just right of `key` after the update. * @dev Note that only one of "lesserKey" or "greaterKey" needs to be correct to reduce friction. */ function update( List storage list, bytes32 key, uint256 value, bytes32 lesserKey, bytes32 greaterKey ) internal { remove(list, key); insert(list, key, value, lesserKey, greaterKey); } /** * @notice Inserts an element at the tail of the doubly linked list. * @param list A storage pointer to the underlying list. * @param key The key of the element to insert. */ function push(List storage list, bytes32 key) internal { insert(list, key, 0, bytes32(0), list.list.tail); } /** * @notice Removes N elements from the head of the list and returns their keys. * @param list A storage pointer to the underlying list. * @param n The number of elements to pop. * @return The keys of the popped elements. */ function popN(List storage list, uint256 n) internal returns (bytes32[] memory) { require(n <= list.list.numElements, "not enough elements"); bytes32[] memory keys = new bytes32[](n); for (uint256 i = 0; i < n; i = i + 1) { bytes32 key = list.list.head; keys[i] = key; remove(list, key); } return keys; } /** * @notice Returns whether or not a particular key is present in the sorted list. * @param list A storage pointer to the underlying list. * @param key The element key. * @return Whether or not the key is in the sorted list. */ function contains(List storage list, bytes32 key) internal view returns (bool) { return list.list.contains(key); } /** * @notice Returns Element based on key. * @param list A storage pointer to the underlying list. * @param key The element key. * @return Whether or not the key is in the sorted list. */ function get(List storage list, bytes32 key) internal view returns (LinkedList.Element memory) { return list.list.get(key); } /** * @notice Returns the value for a particular key in the sorted list. * @param list A storage pointer to the underlying list. * @param key The element key. * @return The element value. */ function getValue(List storage list, bytes32 key) internal view returns (uint256) { return list.values[key]; } /** * @notice Gets all elements from the doubly linked list. * @param list A storage pointer to the underlying list. * @return Array of all keys in the list. * @return Values corresponding to keys, which will be ordered largest to smallest. */ function getElements(List storage list) internal view returns (bytes32[] memory, uint256[] memory) { bytes32[] memory keys = getKeys(list); uint256[] memory values = new uint256[](keys.length); for (uint256 i = 0; i < keys.length; i = i + 1) { values[i] = list.values[keys[i]]; } return (keys, values); } /** * @notice Gets all element keys from the doubly linked list. * @param list A storage pointer to the underlying list. * @return All element keys from head to tail. */ function getKeys(List storage list) internal view returns (bytes32[] memory) { return list.list.getKeys(); } /** * @notice Returns first N greatest elements of the list. * @param list A storage pointer to the underlying list. * @param n The number of elements to return. * @return The keys of the first n elements. * @dev Reverts if n is greater than the number of elements in the list. */ function headN(List storage list, uint256 n) internal view returns (bytes32[] memory) { return list.list.headN(n); } /** * @notice Returns the keys of the elements greaterKey than and less than the provided value. * @param list A storage pointer to the underlying list. * @param value The element value. * @param lesserKey The key of the element which could be just left of the new value. * @param greaterKey The key of the element which could be just right of the new value. * @return The correct lesserKey keys. * @return The correct greaterKey keys. */ function getLesserAndGreater( List storage list, uint256 value, bytes32 lesserKey, bytes32 greaterKey ) private view returns (bytes32, bytes32) { // Check for one of the following conditions and fail if none are met: // 1. The value is less than the current lowest value // 2. The value is greater than the current greatest value // 3. The value is just greater than the value for `lesserKey` // 4. The value is just less than the value for `greaterKey` if (lesserKey == bytes32(0) && isValueBetween(list, value, lesserKey, list.list.tail)) { return (lesserKey, list.list.tail); } else if ( greaterKey == bytes32(0) && isValueBetween(list, value, list.list.head, greaterKey) ) { return (list.list.head, greaterKey); } else if ( lesserKey != bytes32(0) && isValueBetween(list, value, lesserKey, list.list.elements[lesserKey].nextKey) ) { return (lesserKey, list.list.elements[lesserKey].nextKey); } else if ( greaterKey != bytes32(0) && isValueBetween(list, value, list.list.elements[greaterKey].previousKey, greaterKey) ) { return (list.list.elements[greaterKey].previousKey, greaterKey); } require(false, "get lesser and greater failure"); return (0, 0); } /** * @notice Returns whether or not a given element is between two other elements. * @param list A storage pointer to the underlying list. * @param value The element value. * @param lesserKey The key of the element whose value should be lesserKey. * @param greaterKey The key of the element whose value should be greaterKey. * @return True if the given element is between the two other elements. */ function isValueBetween(List storage list, uint256 value, bytes32 lesserKey, bytes32 greaterKey) private view returns (bool) { bool isLesser = lesserKey == bytes32(0) || list.values[lesserKey] <= value; bool isGreater = greaterKey == bytes32(0) || list.values[greaterKey] >= value; return isLesser && isGreater; } }
/contracts/interfaces/IAccount.sol
//SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.11; interface IAccount { function scheduleVotes(address[] calldata group, uint256[] calldata votes) external payable; function scheduleTransfer( address[] calldata fromGroups, uint256[] calldata fromVotes, address[] calldata toGroups, uint256[] calldata toVotess ) external; function scheduleWithdrawals( address beneficiary, address[] calldata group, uint256[] calldata withdrawals ) external; function votePartially( uint256 proposalId, uint256 index, uint256 yesVotes, uint256 noVotes, uint256 abstainVotes ) external; function getTotalCelo() external view returns (uint256); function getCeloForGroup(address) external view returns (uint256); function scheduledVotesForGroup(address group) external view returns (uint256); function scheduledRevokeForGroup(address group) external view returns (uint256); function scheduledWithdrawalsForGroup(address group) external view returns (uint256); }
/contracts/interfaces/IGroupHealth.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.11; interface IGroupHealth { function isGroupValid(address group) external view returns (bool); }
/contracts/interfaces/IManager.sol
//SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.11; interface IManager { function updateHistoryAndReturnLockedStCeloInVoting(address beneficiary) external returns (uint256); function transfer( address from, address to, uint256 amount ) external; function scheduleTransferWithinStrategy( address[] calldata fromGroups, address[] calldata toGroups, uint256[] calldata fromVotes, uint256[] calldata toVotes ) external; function toCelo(uint256 stCeloAmount) external view returns (uint256); function toStakedCelo(uint256 celoAmount) external view returns (uint256); function getReceivableVotesForGroup(address group) external view returns (uint256); }
/contracts/interfaces/ISpecificGroupStrategy.sol
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.11; interface ISpecificGroupStrategy { function generateDepositVoteDistribution( address group, uint256 votes, uint256 stCeloAmount ) external returns (address[] memory finalGroups, uint256[] memory finalVotes); function generateWithdrawalVoteDistribution( address group, uint256 celoWithdrawalAmount, uint256 stCeloWithdrawalAmount, bool isTransfer ) external returns (address[] memory groups, uint256[] memory votes); function isVotedGroup(address group) external view returns (bool); function isBlockedGroup(address group) external view returns (bool); function getStCeloInGroup(address group) external view returns ( uint256 total, uint256 overflow, uint256 unhealthy ); function totalStCeloLocked() external view returns (uint256); function totalStCeloOverflow() external view returns (uint256); function getNumberOfVotedGroups() external view returns (uint256); }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"error","name":"AddressZeroNotAllowed","inputs":[]},{"type":"error","name":"CallerNotManager","inputs":[{"type":"address","name":"caller","internalType":"address"}]},{"type":"error","name":"CallerNotManagerNorStrategy","inputs":[{"type":"address","name":"caller","internalType":"address"}]},{"type":"error","name":"GroupAlreadyAdded","inputs":[{"type":"address","name":"group","internalType":"address"}]},{"type":"error","name":"GroupNotActive","inputs":[{"type":"address","name":"group","internalType":"address"}]},{"type":"error","name":"GroupNotEligible","inputs":[{"type":"address","name":"group","internalType":"address"}]},{"type":"error","name":"HealthyGroup","inputs":[{"type":"address","name":"group","internalType":"address"}]},{"type":"error","name":"InvalidFromGroup","inputs":[{"type":"address","name":"group","internalType":"address"}]},{"type":"error","name":"InvalidToGroup","inputs":[{"type":"address","name":"group","internalType":"address"}]},{"type":"error","name":"NoActiveGroups","inputs":[]},{"type":"error","name":"NotAbleToDistributeVotes","inputs":[]},{"type":"error","name":"NotUnsortedGroup","inputs":[]},{"type":"error","name":"NullAddress","inputs":[]},{"type":"error","name":"RebalanceEnoughStCelo","inputs":[{"type":"address","name":"group","internalType":"address"},{"type":"uint256","name":"actualCelo","internalType":"uint256"},{"type":"uint256","name":"expectedCelo","internalType":"uint256"}]},{"type":"error","name":"RebalanceNoExtraStCelo","inputs":[{"type":"address","name":"group","internalType":"address"},{"type":"uint256","name":"actualCelo","internalType":"uint256"},{"type":"uint256","name":"expectedCelo","internalType":"uint256"}]},{"type":"event","name":"AdminChanged","inputs":[{"type":"address","name":"previousAdmin","internalType":"address","indexed":false},{"type":"address","name":"newAdmin","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"BeaconUpgraded","inputs":[{"type":"address","name":"beacon","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"GroupActivated","inputs":[{"type":"address","name":"group","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"GroupRemoved","inputs":[{"type":"address","name":"group","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ManagerSet","inputs":[{"type":"address","name":"manager","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SortedFlagUpdated","inputs":[{"type":"bool","name":"update","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"Upgraded","inputs":[{"type":"address","name":"implementation","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IAccount"}],"name":"account","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"activateGroup","inputs":[{"type":"address","name":"group","internalType":"address"},{"type":"address","name":"lesser","internalType":"address"},{"type":"address","name":"greater","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deactivateGroup","inputs":[{"type":"address","name":"group","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deactivateUnhealthyGroup","inputs":[{"type":"address","name":"group","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address[]","name":"finalGroups","internalType":"address[]"},{"type":"uint256[]","name":"finalVotes","internalType":"uint256[]"}],"name":"generateDepositVoteDistribution","inputs":[{"type":"uint256","name":"celoAmount","internalType":"uint256"},{"type":"address","name":"depositGroupToIgnore","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address[]","name":"finalGroups","internalType":"address[]"},{"type":"uint256[]","name":"finalVotes","internalType":"uint256[]"}],"name":"generateWithdrawalVoteDistribution","inputs":[{"type":"uint256","name":"celoAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"expectedStCelo","internalType":"uint256"},{"type":"uint256","name":"actualStCelo","internalType":"uint256"}],"name":"getExpectedAndActualStCeloForGroup","inputs":[{"type":"address","name":"group","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"previousAddress","internalType":"address"},{"type":"address","name":"nextAddress","internalType":"address"}],"name":"getGroupPreviousAndNext","inputs":[{"type":"address","name":"group","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"head","internalType":"address"},{"type":"address","name":"previousAddress","internalType":"address"}],"name":"getGroupsHead","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"tail","internalType":"address"},{"type":"address","name":"nextAddress","internalType":"address"}],"name":"getGroupsTail","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getNumberOfGroups","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getNumberOfUnsortedGroups","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getUnsortedGroupAt","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getVersionNumber","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IGroupHealth"}],"name":"groupHealth","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"address","name":"_manager","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isActive","inputs":[{"type":"address","name":"group","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"manager","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxGroupsToDistributeTo","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxGroupsToWithdrawFrom","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rebalance","inputs":[{"type":"address","name":"fromGroup","internalType":"address"},{"type":"address","name":"toGroup","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDependencies","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"address","name":"_groupHealth","internalType":"address"},{"type":"address","name":"_specificGroupStrategy","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setManager","inputs":[{"type":"address","name":"_manager","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSortingParams","inputs":[{"type":"uint256","name":"distributeTo","internalType":"uint256"},{"type":"uint256","name":"withdrawFrom","internalType":"uint256"},{"type":"uint256","name":"loopLimit","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"sorted","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ISpecificGroupStrategy"}],"name":"specificGroupStrategy","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stCeloInGroup","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalStCeloInStrategy","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateActiveGroupOrder","inputs":[{"type":"address","name":"group","internalType":"address"},{"type":"address","name":"lesserKey","internalType":"address"},{"type":"address","name":"greaterKey","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"upgradeTo","inputs":[{"type":"address","name":"newImplementation","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"upgradeToAndCall","inputs":[{"type":"address","name":"newImplementation","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"}]}]
Contract Creation Code
0x60a06040523073ffffffffffffffffffffffffffffffffffffffff1660809073ffffffffffffffffffffffffffffffffffffffff168152503480156200004457600080fd5b50600060019054906101000a900460ff166200006f5760008054906101000a900460ff161562000080565b6200007f6200013c60201b60201c565b5b620000c2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620000b99062000204565b60405180910390fd5b60008060019054906101000a900460ff16159050801562000113576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b8015620001355760008060016101000a81548160ff0219169083151502179055505b5062000226565b600062000154306200015a60201b62002b6e1760201c565b15905090565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b600082825260208201905092915050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b6000620001ec602e836200017d565b9150620001f9826200018e565b604082019050919050565b600060208201905081810360008301526200021f81620001dd565b9050919050565b608051615a2d6200025760003960008181610861015281816108f0015281816114a601526115350152615a2d6000f3fe6080604052600436106101f95760003560e01c8063885640db1161010d578063c1fa411a116100a0578063d2a2ce5d1161006f578063d2a2ce5d1461071c578063dcdab02a14610747578063e0cd8d2714610770578063eccacf7f146107ae578063f2fde38b146107d9576101f9565b8063c1fa411a14610671578063c5728c831461069c578063cf009f7a146106c8578063d0ebdbe7146106f3576101f9565b8063a3f16ef1116100dc578063a3f16ef1146105b6578063afc97578146105e1578063b52d326c1461060a578063be982c3114610633576101f9565b8063885640db146104fc5780638da5cb5b1461052557806393739a93146105505780639f8a13d714610579576101f9565b80634f1ef286116101905780635dab24201161015f5780635dab2420146104285780636fe958d814610453578063715018a61461047c578063724e61d01461049357806385a92cb7146104bf576101f9565b80634f1ef2861461038a5780634fc517eb146103a65780635145b0ad146103d157806354255be0146103fa576101f9565b80633659cfe6116101cc5780633659cfe6146102cf57806336691a41146102f8578063481c6a7514610336578063485cc95514610361576101f9565b80630c29aab2146101fe5780630f8f0fcc146102295780632863f68c146102665780632de2c5ac146102a4575b600080fd5b34801561020a57600080fd5b50610213610802565b6040516102209190614732565b60405180910390f35b34801561023557600080fd5b50610250600480360381019061024b919061478d565b610808565b60405161025d91906147fb565b60405180910390f35b34801561027257600080fd5b5061028d60048036038101906102889190614842565b610825565b60405161029b92919061486f565b60405180910390f35b3480156102b057600080fd5b506102b961084c565b6040516102c691906148b3565b60405180910390f35b3480156102db57600080fd5b506102f660048036038101906102f19190614842565b61085f565b005b34801561030457600080fd5b5061031f600480360381019061031a919061478d565b6109e8565b60405161032d929190614a4a565b60405180910390f35b34801561034257600080fd5b5061034b61130d565b60405161035891906147fb565b60405180910390f35b34801561036d57600080fd5b5061038860048036038101906103839190614a81565b611333565b005b6103a4600480360381019061039f9190614c07565b6114a4565b005b3480156103b257600080fd5b506103bb6115e1565b6040516103c89190614732565b60405180910390f35b3480156103dd57600080fd5b506103f860048036038101906103f39190614c63565b6115e7565b005b34801561040657600080fd5b5061040f611770565b60405161041f9493929190614cb6565b60405180910390f35b34801561043457600080fd5b5061043d61178a565b60405161044a9190614d5a565b60405180910390f35b34801561045f57600080fd5b5061047a60048036038101906104759190614a81565b6117b0565b005b34801561048857600080fd5b50610491611ab7565b005b34801561049f57600080fd5b506104a8611b3f565b6040516104b692919061486f565b60405180910390f35b3480156104cb57600080fd5b506104e660048036038101906104e19190614842565b611bdf565b6040516104f39190614732565b60405180910390f35b34801561050857600080fd5b50610523600480360381019061051e9190614d75565b611bf7565b005b34801561053157600080fd5b5061053a611c8d565b60405161054791906147fb565b60405180910390f35b34801561055c57600080fd5b5061057760048036038101906105729190614842565b611cb7565b005b34801561058557600080fd5b506105a0600480360381019061059b9190614842565b611d3f565b6040516105ad91906148b3565b60405180910390f35b3480156105c257600080fd5b506105cb611dc5565b6040516105d89190614de9565b60405180910390f35b3480156105ed57600080fd5b5061060860048036038101906106039190614c63565b611deb565b005b34801561061657600080fd5b50610631600480360381019061062c9190614c63565b6122ca565b005b34801561063f57600080fd5b5061065a60048036038101906106559190614842565b6124e3565b604051610668929190614e04565b60405180910390f35b34801561067d57600080fd5b5061068661269e565b6040516106939190614732565b60405180910390f35b3480156106a857600080fd5b506106b1612720565b6040516106bf92919061486f565b60405180910390f35b3480156106d457600080fd5b506106dd6127c1565b6040516106ea9190614e4e565b60405180910390f35b3480156106ff57600080fd5b5061071a60048036038101906107159190614842565b6127e7565b005b34801561072857600080fd5b5061073161286f565b60405161073e9190614732565b60405180910390f35b34801561075357600080fd5b5061076e60048036038101906107699190614842565b612880565b005b34801561077c57600080fd5b5061079760048036038101906107929190614e69565b61296a565b6040516107a5929190614a4a565b60405180910390f35b3480156107ba57600080fd5b506107c3612a70565b6040516107d09190614732565b60405180910390f35b3480156107e557600080fd5b5061080060048036038101906107fb9190614842565b612a76565b005b60715481565b600061081e826074612b9190919063ffffffff16565b9050919050565b60008061083c836066612bab90919063ffffffff16565b9091508092508193505050915091565b607360009054906101000a900460ff1681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614156108ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e590614f2c565b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1661092d612c06565b73ffffffffffffffffffffffffffffffffffffffff1614610983576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097a90614fbe565b60405180910390fd5b61098c81612c5d565b6109e581600067ffffffffffffffff8111156109ab576109aa614adc565b5b6040519080825280601f01601f1916602001820160405280156109dd5781602001600182028036833780820191505090505b506000612cdc565b50565b6060803373ffffffffffffffffffffffffffffffffffffffff16606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614158015610a9757503373ffffffffffffffffffffffffffffffffffffffff16606d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b15610ad957336040517f79eaeb2b000000000000000000000000000000000000000000000000000000008152600401610ad091906147fb565b60405180910390fd5b60006066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b8152600401610b159190614fe5565b602060405180830381865af4158015610b32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b569190615015565b1415610b8e576040517f7818a60e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610c166070546066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b8152600401610bd09190614fe5565b602060405180830381865af4158015610bed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c119190615015565b612ead565b905060008167ffffffffffffffff811115610c3457610c33614adc565b5b604051908082528060200260200182016040528015610c625781602001602082028036833780820191505090505b50905060008267ffffffffffffffff811115610c8157610c80614adc565b5b604051908082528060200260200182016040528015610caf5781602001602082028036833780820191505090505b50905060006066731076d108448175dfcf0be58314bbfdb865d2f7ec630c8f298790916040518263ffffffff1660e01b8152600401610cee9190614fe5565b602060405180830381865af4158015610d0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2f9190615057565b905060005b8481108015610d44575060008814155b8015610d7d5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b1561117257610f0a610f04606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663acd201d0856040518263ffffffff1660e01b8152600401610de391906147fb565b602060405180830381865afa158015610e00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e249190615015565b606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630567847f606e60008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518263ffffffff1660e01b8152600401610ebe9190614732565b602060405180830381865afa158015610edb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eff9190615015565b612ead565b89612ead565b838281518110610f1d57610f1c615084565b5b60200260200101818152505081848281518110610f3d57610f3c615084565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828181518110610f8a57610f89615084565b5b602002602001015188610f9d91906150e2565b975061106082606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c494ec1e868581518110610ff457610ff3615084565b5b60200260200101516040518263ffffffff1660e01b81526004016110189190614732565b602060405180830381865afa158015611035573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110599190615015565b6000612ec6565b6110ab82606e60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546000612fb5565b607360009054906101000a900460ff1615611142576066731076d108448175dfcf0be58314bbfdb865d2f7ec630c8f298790916040518263ffffffff1660e01b81526004016110fa9190614fe5565b602060405180830381865af4158015611117573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113b9190615057565b915061115f565b611156826066612bab90919063ffffffff16565b90915050809250505b808061116a90615116565b915050610d34565b600088146111ac576040517f2e6c1bf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff8111156111c6576111c5614adc565b5b6040519080825280602002602001820160405280156111f45781602001602082028036833780820191505090505b5096508067ffffffffffffffff81111561121157611210614adc565b5b60405190808252806020026020018201604052801561123f5781602001602082028036833780820191505090505b50955060005b81811015611302578481815181106112605761125f615084565b5b602002602001015188828151811061127b5761127a615084565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508381815181106112c8576112c7615084565b5b60200260200101518782815181106112e3576112e2615084565b5b60200260200101818152505080806112fa90615116565b915050611245565b505050505050915091565b606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060019054906101000a900460ff1661135b5760008054906101000a900460ff1615611364565b611363613269565b5b6113a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161139a906151d1565b60405180910390fd5b60008060019054906101000a900460ff1615905080156113f3576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b6113fc8361327a565b61140582613340565b6008606f819055506008607081905550600a6072819055506001607360006101000a81548160ff0219169083151502179055507fb930683f0749189780c4016ec37d019eb0cbbf6550ce7374fac5cfbae93909a7607360009054906101000a900460ff1660405161147691906148b3565b60405180910390a1801561149f5760008060016101000a81548160ff0219169083151502179055505b505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff161415611533576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161152a90614f2c565b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16611572612c06565b73ffffffffffffffffffffffffffffffffffffffff16146115c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115bf90614fbe565b60405180910390fd5b6115d182612c5d565b6115dd82826001612cdc565b5050565b606f5481565b6115fb83607461339b90919063ffffffff16565b611631576040517f0a1f2c0e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6066731076d108448175dfcf0be58314bbfdb865d2f7ec63cab455ae909185606e60008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205486866040518663ffffffff1660e01b81526004016116b295949392919061520f565b60006040518083038186803b1580156116ca57600080fd5b505af41580156116de573d6000803e3d6000fd5b505050506116f68360746133cb90919063ffffffff16565b50600061170360746133fb565b141561176b576001607360006101000a81548160ff0219169083151502179055507fb930683f0749189780c4016ec37d019eb0cbbf6550ce7374fac5cfbae93909a7607360009054906101000a900460ff1660405161176291906148b3565b60405180910390a15b505050565b600080600080600180600080935093509350935090919293565b606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6066731076d108448175dfcf0be58314bbfdb865d2f7ec6302f130289091846040518363ffffffff1660e01b81526004016117ec929190615262565b602060405180830381865af4158015611809573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182d91906152b7565b61186e57816040517fdc1b434d00000000000000000000000000000000000000000000000000000000815260040161186591906147fb565b60405180910390fd5b6066731076d108448175dfcf0be58314bbfdb865d2f7ec6302f130289091836040518363ffffffff1660e01b81526004016118aa929190615262565b602060405180830381865af41580156118c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118eb91906152b7565b61192c57806040517f5a08158400000000000000000000000000000000000000000000000000000000815260040161192391906147fb565b60405180910390fd5b600080611938846124e3565b91509150818111611984578381836040517f8b0123bf00000000000000000000000000000000000000000000000000000000815260040161197b939291906152e4565b60405180910390fd5b600080611990856124e3565b915091508181106119dc578481836040517f845286390000000000000000000000000000000000000000000000000000000081526004016119d3939291906152e4565b60405180910390fd5b60006119fe85856119ed91906150e2565b83856119f991906150e2565b612ead565b9050611a0c87826000612ec6565b611a1886826001612ec6565b611a6387606e60008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546000612fb5565b611aae86606e60008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546001612fb5565b50505050505050565b611abf613410565b73ffffffffffffffffffffffffffffffffffffffff16611add611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614611b33576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b2a90615367565b60405180910390fd5b611b3d600061327a565b565b6000806066731076d108448175dfcf0be58314bbfdb865d2f7ec630c8f298790916040518263ffffffff1660e01b8152600401611b7c9190614fe5565b602060405180830381865af4158015611b99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bbd9190615057565b9150611bd3826066612bab90919063ffffffff16565b90915050809150509091565b606e6020528060005260406000206000915090505481565b611bff613410565b73ffffffffffffffffffffffffffffffffffffffff16611c1d611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614611c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c6a90615367565b60405180910390fd5b82606f819055508160708190555080607281905550505050565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611cbf613410565b73ffffffffffffffffffffffffffffffffffffffff16611cdd611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614611d33576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d2a90615367565b60405180910390fd5b611d3c81613418565b50565b60006066731076d108448175dfcf0be58314bbfdb865d2f7ec6302f130289091846040518363ffffffff1660e01b8152600401611d7d929190615262565b602060405180830381865af4158015611d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbe91906152b7565b9050919050565b606b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b611df3613410565b73ffffffffffffffffffffffffffffffffffffffff16611e11611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614611e67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e5e90615367565b60405180910390fd5b606b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ac8f4425846040518263ffffffff1660e01b8152600401611ec291906147fb565b602060405180830381865afa158015611edf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0391906152b7565b611f4457826040517f10a7bc6b000000000000000000000000000000000000000000000000000000008152600401611f3b91906147fb565b60405180910390fd5b6066731076d108448175dfcf0be58314bbfdb865d2f7ec6302f130289091856040518363ffffffff1660e01b8152600401611f80929190615262565b602060405180830381865af4158015611f9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc191906152b7565b1561200357826040517fbd133eee000000000000000000000000000000000000000000000000000000008152600401611ffa91906147fb565b60405180910390fd5b600080606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c494ec1e606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663acd201d0886040518263ffffffff1660e01b815260040161209f91906147fb565b602060405180830381865afa1580156120bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e09190615015565b6040518263ffffffff1660e01b81526004016120fc9190614732565b602060405180830381865afa158015612119573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213d9190615015565b90506000811461220e576000606d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166356ab819f876040518263ffffffff1660e01b81526004016121a491906147fb565b606060405180830381865afa1580156121c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e59190615387565b505090506121f38282612ead565b826121fe91906150e2565b925061220c86846001612ec6565b505b6066731076d108448175dfcf0be58314bbfdb865d2f7ec632dedbbf09091878588886040518663ffffffff1660e01b815260040161225095949392919061520f565b60006040518083038186803b15801561226857600080fd5b505af415801561227c573d6000803e3d6000fd5b505050508473ffffffffffffffffffffffffffffffffffffffff167f0503b4748a47435f2432d46ef300e0e2dc47baa0e5f04bb3bd8a355ee1e1dbe660405160405180910390a25050505050565b6122d2613410565b73ffffffffffffffffffffffffffffffffffffffff166122f0611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614612346576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161233d90615367565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614806123ad5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b806123e45750600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b1561241b576040517f0855380c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81606b60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080606d60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082606c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505050565b60008060006066731076d108448175dfcf0be58314bbfdb865d2f7ec630c8f298790916040518263ffffffff1660e01b81526004016125229190614fe5565b602060405180830381865af415801561253f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125639190615057565b905060006066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b81526004016125a19190614fe5565b602060405180830381865af41580156125be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125e29190615015565b9050806071546125f29190615409565b93508173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614156126555760008185612636919061543a565b60715461264391906150e2565b905080856126519190615494565b9450505b606e60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205492505050915091565b60006066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b81526004016126da9190614fe5565b602060405180830381865af41580156126f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061271b9190615015565b905090565b6000806066731076d108448175dfcf0be58314bbfdb865d2f7ec6349923bff90916040518263ffffffff1660e01b815260040161275d9190614fe5565b602060405180830381865af415801561277a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279e9190615057565b91506127b4826066612bab90919063ffffffff16565b9091509050809150509091565b606d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6127ef613410565b73ffffffffffffffffffffffffffffffffffffffff1661280d611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614612863576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161285a90615367565b60405180910390fd5b61286c816138e3565b50565b600061287b60746133fb565b905090565b606b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ac8f4425826040518263ffffffff1660e01b81526004016128db91906147fb565b602060405180830381865afa1580156128f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291c91906152b7565b1561295e57806040517fe3bd013b00000000000000000000000000000000000000000000000000000000815260040161295591906147fb565b60405180910390fd5b61296781613418565b50565b6060803373ffffffffffffffffffffffffffffffffffffffff16606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614158015612a1957503373ffffffffffffffffffffffffffffffffffffffff16606d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b15612a5b57336040517f79eaeb2b000000000000000000000000000000000000000000000000000000008152600401612a5291906147fb565b60405180910390fd5b612a6584846139d1565b915091509250929050565b60705481565b612a7e613410565b73ffffffffffffffffffffffffffffffffffffffff16612a9c611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614612af2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ae990615367565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612b62576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b599061555c565b60405180910390fd5b612b6b8161327a565b50565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000612ba08360000183614190565b60001c905092915050565b600080600080612bcc612bbd866141bb565b876141e290919063ffffffff16565b905080604001519350806040015115612bfe57612bec8160000151614208565b9250612bfb8160200151614208565b91505b509250925092565b6000612c347f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b614219565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b612c65613410565b73ffffffffffffffffffffffffffffffffffffffff16612c83611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614612cd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cd090615367565b60405180910390fd5b50565b6000612ce6612c06565b9050612cf184614223565b600083511180612cfe5750815b15612d0f57612d0d84846142dc565b505b6000612d3d7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd914360001b614309565b90508060000160009054906101000a900460ff16612ea65760018160000160006101000a81548160ff021916908315150217905550612e098583604051602401612d8791906147fb565b6040516020818303038152906040527f3659cfe6000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506142dc565b5060008160000160006101000a81548160ff021916908315150217905550612e2f612c06565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614612e9c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e93906155ee565b60405180910390fd5b612ea585614313565b5b5050505050565b6000818310612ebc5781612ebe565b825b905092915050565b8015612f405781606e60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612f1b9190615494565b925050819055508160716000828254612f349190615494565b92505081905550612fb0565b81606e60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612f8f91906150e2565b925050819055508160716000828254612fa891906150e2565b925050819055505b505050565b612fc983607461339b90919063ffffffff16565b15612fd357613264565b60008082613062576066731076d108448175dfcf0be58314bbfdb865d2f7ec63a4aadfcc909187876072546040518563ffffffff1660e01b815260040161301d949392919061560e565b6040805180830381865af4158015613039573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061305d9190615653565b6130e5565b6066731076d108448175dfcf0be58314bbfdb865d2f7ec6399f68a39909187876072546040518563ffffffff1660e01b81526004016130a4949392919061560e565b6040805180830381865af41580156130c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130e49190615653565b5b915091508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158061319e575060016066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b815260040161315b9190614fe5565b602060405180830381865af4158015613178573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061319c9190615015565b145b1561321a576066731076d108448175dfcf0be58314bbfdb865d2f7ec63cab455ae9091878786866040518663ffffffff1660e01b81526004016131e595949392919061520f565b60006040518083038186803b1580156131fd57600080fd5b505af4158015613211573d6000803e3d6000fd5b50505050613261565b607360009054906101000a900460ff161561324b576000607360006101000a81548160ff0219169083151502179055505b61325f85607461436290919063ffffffff16565b505b50505b505050565b600061327430612b6e565b15905090565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081603360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600060019054906101000a900460ff1661338f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161338690615705565b60405180910390fd5b613398816138e3565b50565b60006133c3836000018373ffffffffffffffffffffffffffffffffffffffff1660001b614392565b905092915050565b60006133f3836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6143b5565b905092915050565b6000613409826000016144c9565b9050919050565b600033905090565b6066731076d108448175dfcf0be58314bbfdb865d2f7ec6302f130289091836040518363ffffffff1660e01b8152600401613454929190615262565b602060405180830381865af4158015613471573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349591906152b7565b6134d657806040517f1adbb1530000000000000000000000000000000000000000000000000000000081526004016134cd91906147fb565b60405180910390fd5b6066731076d108448175dfcf0be58314bbfdb865d2f7ec63281359299091836040518363ffffffff1660e01b8152600401613512929190615262565b60006040518083038186803b15801561352a57600080fd5b505af415801561353e573d6000803e3d6000fd5b505050506135568160746133cb90919063ffffffff16565b506000606e60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600081111561389c576135b082826000612ec6565b6000600167ffffffffffffffff8111156135cd576135cc614adc565b5b6040519080825280602002602001820160405280156135fb5781602001602082028036833780820191505090505b5090506000600167ffffffffffffffff81111561361b5761361a614adc565b5b6040519080825280602002602001820160405280156136495781602001602082028036833780820191505090505b509050838260008151811061366157613660615084565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630567847f846040518263ffffffff1660e01b81526004016136f69190614732565b602060405180830381865afa158015613713573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137379190615015565b8160008151811061374b5761374a615084565b5b602002602001018181525050600080613800606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630567847f876040518263ffffffff1660e01b81526004016137b89190614732565b602060405180830381865afa1580156137d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f99190615015565b60006139d1565b91509150606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c4d4e40858486856040518563ffffffff1660e01b81526004016138659493929190615725565b600060405180830381600087803b15801561387f57600080fd5b505af1158015613893573d6000803e3d6000fd5b50505050505050505b8173ffffffffffffffffffffffffffffffffffffffff167fa78a88a551e130ce9732be17784bdff12f72ab4a2c833fb2dcb3ef0818956b0360405160405180910390a25050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561394a576040517fe99d5ac500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80606560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f60a0f5b9f9e81e98216071b85826681c796256fe3d1354ecb675580fba64fa6960405160405180910390a250565b60608060006066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b8152600401613a109190614fe5565b602060405180830381865af4158015613a2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a519190615015565b1415613a89576040517f7818a60e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613b11606f546066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b8152600401613acb9190614fe5565b602060405180830381865af4158015613ae8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b0c9190615015565b612ead565b905060008167ffffffffffffffff811115613b2f57613b2e614adc565b5b604051908082528060200260200182016040528015613b5d5781602001602082028036833780820191505090505b50905060008267ffffffffffffffff811115613b7c57613b7b614adc565b5b604051908082528060200260200182016040528015613baa5781602001602082028036833780820191505090505b50905060006066731076d108448175dfcf0be58314bbfdb865d2f7ec6349923bff90916040518263ffffffff1660e01b8152600401613be99190614fe5565b602060405180830381865af4158015613c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2a9190615057565b905060005b8481108015613c3f575060008914155b8015613c785750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15613ff3576000606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632c431058846040518263ffffffff1660e01b8152600401613cda91906147fb565b602060405180830381865afa158015613cf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d1b9190615015565b90508873ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480613d575750600081145b15613d7f57613d70836066612bab90919063ffffffff16565b90915090508093505050613c2f565b613d89818b612ead565b848381518110613d9c57613d9b615084565b5b60200260200101818152505082858381518110613dbc57613dbb615084565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050838281518110613e0957613e08615084565b5b60200260200101518a613e1c91906150e2565b9950613edf83606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c494ec1e878681518110613e7357613e72615084565b5b60200260200101516040518263ffffffff1660e01b8152600401613e979190614732565b602060405180830381865afa158015613eb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ed89190615015565b6001612ec6565b613f2a83606e60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546001612fb5565b607360009054906101000a900460ff1615613fc1576066731076d108448175dfcf0be58314bbfdb865d2f7ec6349923bff90916040518263ffffffff1660e01b8152600401613f799190614fe5565b602060405180830381865af4158015613f96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fba9190615057565b9250613fdf565b613fd5836066612bab90919063ffffffff16565b9091509050809350505b8180613fea90615116565b92505050613c2f565b6000891461402d576040517f2e6c1bf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff81111561404757614046614adc565b5b6040519080825280602002602001820160405280156140755781602001602082028036833780820191505090505b5096508067ffffffffffffffff81111561409257614091614adc565b5b6040519080825280602002602001820160405280156140c05781602001602082028036833780820191505090505b50955060005b81811015614183578481815181106140e1576140e0615084565b5b60200260200101518882815181106140fc576140fb615084565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083818151811061414957614148615084565b5b602002602001015187828151811061416457614163615084565b5b602002602001018181525050808061417b90615116565b9150506140c6565b5050505050509250929050565b60008260000182815481106141a8576141a7615084565b5b9060005260206000200154905092915050565b600060608273ffffffffffffffffffffffffffffffffffffffff16901b60001b9050919050565b6141ea6146f0565b61420082846000016144da90919063ffffffff16565b905092915050565b600060608260001c901c9050919050565b6000819050919050565b61422c81614539565b61426b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401614262906157f8565b60405180910390fd5b806142987f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b614219565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b606061430183836040518060600160405280602781526020016159d16027913961454c565b905092915050565b6000819050919050565b61431c81614223565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b600061438a836000018373ffffffffffffffffffffffffffffffffffffffff1660001b614619565b905092915050565b600080836001016000848152602001908152602001600020541415905092915050565b600080836001016000848152602001908152602001600020549050600081146144bd5760006001826143e791906150e2565b90506000600186600001805490506143ff91906150e2565b905081811461446e5760008660000182815481106144205761441f615084565b5b906000526020600020015490508087600001848154811061444457614443615084565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b8560000180548061448257614481615818565b5b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506144c3565b60009150505b92915050565b600081600001805490509050919050565b6144e26146f0565b82600301600083815260200190815260200160002060405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900460ff161515151581525050905092915050565b600080823b905060008111915050919050565b606061455784614539565b614596576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161458d906158b9565b60405180910390fd5b6000808573ffffffffffffffffffffffffffffffffffffffff16856040516145be9190615953565b600060405180830381855af49150503d80600081146145f9576040519150601f19603f3d011682016040523d82523d6000602084013e6145fe565b606091505b509150915061460e828286614689565b925050509392505050565b60006146258383614392565b61467e578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050614683565b600090505b92915050565b60608315614699578290506146e9565b6000835111156146ac5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016146e091906159ae565b60405180910390fd5b9392505050565b604051806060016040528060008019168152602001600080191681526020016000151581525090565b6000819050919050565b61472c81614719565b82525050565b60006020820190506147476000830184614723565b92915050565b6000604051905090565b600080fd5b600080fd5b61476a81614719565b811461477557600080fd5b50565b60008135905061478781614761565b92915050565b6000602082840312156147a3576147a2614757565b5b60006147b184828501614778565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006147e5826147ba565b9050919050565b6147f5816147da565b82525050565b600060208201905061481060008301846147ec565b92915050565b61481f816147da565b811461482a57600080fd5b50565b60008135905061483c81614816565b92915050565b60006020828403121561485857614857614757565b5b60006148668482850161482d565b91505092915050565b600060408201905061488460008301856147ec565b61489160208301846147ec565b9392505050565b60008115159050919050565b6148ad81614898565b82525050565b60006020820190506148c860008301846148a4565b92915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b614903816147da565b82525050565b600061491583836148fa565b60208301905092915050565b6000602082019050919050565b6000614939826148ce565b61494381856148d9565b935061494e836148ea565b8060005b8381101561497f5781516149668882614909565b975061497183614921565b925050600181019050614952565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6149c181614719565b82525050565b60006149d383836149b8565b60208301905092915050565b6000602082019050919050565b60006149f78261498c565b614a018185614997565b9350614a0c836149a8565b8060005b83811015614a3d578151614a2488826149c7565b9750614a2f836149df565b925050600181019050614a10565b5085935050505092915050565b60006040820190508181036000830152614a64818561492e565b90508181036020830152614a7881846149ec565b90509392505050565b60008060408385031215614a9857614a97614757565b5b6000614aa68582860161482d565b9250506020614ab78582860161482d565b9150509250929050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b614b1482614acb565b810181811067ffffffffffffffff82111715614b3357614b32614adc565b5b80604052505050565b6000614b4661474d565b9050614b528282614b0b565b919050565b600067ffffffffffffffff821115614b7257614b71614adc565b5b614b7b82614acb565b9050602081019050919050565b82818337600083830152505050565b6000614baa614ba584614b57565b614b3c565b905082815260208101848484011115614bc657614bc5614ac6565b5b614bd1848285614b88565b509392505050565b600082601f830112614bee57614bed614ac1565b5b8135614bfe848260208601614b97565b91505092915050565b60008060408385031215614c1e57614c1d614757565b5b6000614c2c8582860161482d565b925050602083013567ffffffffffffffff811115614c4d57614c4c61475c565b5b614c5985828601614bd9565b9150509250929050565b600080600060608486031215614c7c57614c7b614757565b5b6000614c8a8682870161482d565b9350506020614c9b8682870161482d565b9250506040614cac8682870161482d565b9150509250925092565b6000608082019050614ccb6000830187614723565b614cd86020830186614723565b614ce56040830185614723565b614cf26060830184614723565b95945050505050565b6000819050919050565b6000614d20614d1b614d16846147ba565b614cfb565b6147ba565b9050919050565b6000614d3282614d05565b9050919050565b6000614d4482614d27565b9050919050565b614d5481614d39565b82525050565b6000602082019050614d6f6000830184614d4b565b92915050565b600080600060608486031215614d8e57614d8d614757565b5b6000614d9c86828701614778565b9350506020614dad86828701614778565b9250506040614dbe86828701614778565b9150509250925092565b6000614dd382614d27565b9050919050565b614de381614dc8565b82525050565b6000602082019050614dfe6000830184614dda565b92915050565b6000604082019050614e196000830185614723565b614e266020830184614723565b9392505050565b6000614e3882614d27565b9050919050565b614e4881614e2d565b82525050565b6000602082019050614e636000830184614e3f565b92915050565b60008060408385031215614e8057614e7f614757565b5b6000614e8e85828601614778565b9250506020614e9f8582860161482d565b9150509250929050565b600082825260208201905092915050565b7f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060008201527f64656c656761746563616c6c0000000000000000000000000000000000000000602082015250565b6000614f16602c83614ea9565b9150614f2182614eba565b604082019050919050565b60006020820190508181036000830152614f4581614f09565b9050919050565b7f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060008201527f6163746976652070726f78790000000000000000000000000000000000000000602082015250565b6000614fa8602c83614ea9565b9150614fb382614f4c565b604082019050919050565b60006020820190508181036000830152614fd781614f9b565b9050919050565b8082525050565b6000602082019050614ffa6000830184614fde565b92915050565b60008151905061500f81614761565b92915050565b60006020828403121561502b5761502a614757565b5b600061503984828501615000565b91505092915050565b60008151905061505181614816565b92915050565b60006020828403121561506d5761506c614757565b5b600061507b84828501615042565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006150ed82614719565b91506150f883614719565b92508282101561510b5761510a6150b3565b5b828203905092915050565b600061512182614719565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415615154576151536150b3565b5b600182019050919050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b60006151bb602e83614ea9565b91506151c68261515f565b604082019050919050565b600060208201905081810360008301526151ea816151ae565b9050919050565b6151fa816147da565b82525050565b61520981614719565b82525050565b600060a0820190506152246000830188614fde565b61523160208301876151f1565b61523e6040830186615200565b61524b60608301856151f1565b61525860808301846151f1565b9695505050505050565b60006040820190506152776000830185614fde565b61528460208301846151f1565b9392505050565b61529481614898565b811461529f57600080fd5b50565b6000815190506152b18161528b565b92915050565b6000602082840312156152cd576152cc614757565b5b60006152db848285016152a2565b91505092915050565b60006060820190506152f960008301866147ec565b6153066020830185614723565b6153136040830184614723565b949350505050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000615351602083614ea9565b915061535c8261531b565b602082019050919050565b6000602082019050818103600083015261538081615344565b9050919050565b6000806000606084860312156153a05761539f614757565b5b60006153ae86828701615000565b93505060206153bf86828701615000565b92505060406153d086828701615000565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061541482614719565b915061541f83614719565b92508261542f5761542e6153da565b5b828204905092915050565b600061544582614719565b915061545083614719565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615489576154886150b3565b5b828202905092915050565b600061549f82614719565b91506154aa83614719565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156154df576154de6150b3565b5b828201905092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000615546602683614ea9565b9150615551826154ea565b604082019050919050565b6000602082019050818103600083015261557581615539565b9050919050565b7f45524331393637557067726164653a207570677261646520627265616b73206660008201527f7572746865722075706772616465730000000000000000000000000000000000602082015250565b60006155d8602f83614ea9565b91506155e38261557c565b604082019050919050565b60006020820190508181036000830152615607816155cb565b9050919050565b60006080820190506156236000830187614fde565b61563060208301866151f1565b61563d6040830185615200565b61564a6060830184615200565b95945050505050565b6000806040838503121561566a57615669614757565b5b600061567885828601615042565b925050602061568985828601615042565b9150509250929050565b7f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960008201527f6e697469616c697a696e67000000000000000000000000000000000000000000602082015250565b60006156ef602b83614ea9565b91506156fa82615693565b604082019050919050565b6000602082019050818103600083015261571e816156e2565b9050919050565b6000608082019050818103600083015261573f818761492e565b90508181036020830152615753818661492e565b9050818103604083015261576781856149ec565b9050818103606083015261577b81846149ec565b905095945050505050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b60006157e2602d83614ea9565b91506157ed82615786565b604082019050919050565b60006020820190508181036000830152615811816157d5565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60008201527f6e74726163740000000000000000000000000000000000000000000000000000602082015250565b60006158a3602683614ea9565b91506158ae82615847565b604082019050919050565b600060208201905081810360008301526158d281615896565b9050919050565b600081519050919050565b600081905092915050565b60005b8381101561590d5780820151818401526020810190506158f2565b8381111561591c576000848401525b50505050565b600061592d826158d9565b61593781856158e4565b93506159478185602086016158ef565b80840191505092915050565b600061595f8284615922565b915081905092915050565b600081519050919050565b60006159808261596a565b61598a8185614ea9565b935061599a8185602086016158ef565b6159a381614acb565b840191505092915050565b600060208201905081810360008301526159c88184615975565b90509291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220a1703fc71954cbb1a1560d4385dc2ddecc730aa26a4d16d5f09db1ec2697648464736f6c634300080b0033
Deployed ByteCode
0x6080604052600436106101f95760003560e01c8063885640db1161010d578063c1fa411a116100a0578063d2a2ce5d1161006f578063d2a2ce5d1461071c578063dcdab02a14610747578063e0cd8d2714610770578063eccacf7f146107ae578063f2fde38b146107d9576101f9565b8063c1fa411a14610671578063c5728c831461069c578063cf009f7a146106c8578063d0ebdbe7146106f3576101f9565b8063a3f16ef1116100dc578063a3f16ef1146105b6578063afc97578146105e1578063b52d326c1461060a578063be982c3114610633576101f9565b8063885640db146104fc5780638da5cb5b1461052557806393739a93146105505780639f8a13d714610579576101f9565b80634f1ef286116101905780635dab24201161015f5780635dab2420146104285780636fe958d814610453578063715018a61461047c578063724e61d01461049357806385a92cb7146104bf576101f9565b80634f1ef2861461038a5780634fc517eb146103a65780635145b0ad146103d157806354255be0146103fa576101f9565b80633659cfe6116101cc5780633659cfe6146102cf57806336691a41146102f8578063481c6a7514610336578063485cc95514610361576101f9565b80630c29aab2146101fe5780630f8f0fcc146102295780632863f68c146102665780632de2c5ac146102a4575b600080fd5b34801561020a57600080fd5b50610213610802565b6040516102209190614732565b60405180910390f35b34801561023557600080fd5b50610250600480360381019061024b919061478d565b610808565b60405161025d91906147fb565b60405180910390f35b34801561027257600080fd5b5061028d60048036038101906102889190614842565b610825565b60405161029b92919061486f565b60405180910390f35b3480156102b057600080fd5b506102b961084c565b6040516102c691906148b3565b60405180910390f35b3480156102db57600080fd5b506102f660048036038101906102f19190614842565b61085f565b005b34801561030457600080fd5b5061031f600480360381019061031a919061478d565b6109e8565b60405161032d929190614a4a565b60405180910390f35b34801561034257600080fd5b5061034b61130d565b60405161035891906147fb565b60405180910390f35b34801561036d57600080fd5b5061038860048036038101906103839190614a81565b611333565b005b6103a4600480360381019061039f9190614c07565b6114a4565b005b3480156103b257600080fd5b506103bb6115e1565b6040516103c89190614732565b60405180910390f35b3480156103dd57600080fd5b506103f860048036038101906103f39190614c63565b6115e7565b005b34801561040657600080fd5b5061040f611770565b60405161041f9493929190614cb6565b60405180910390f35b34801561043457600080fd5b5061043d61178a565b60405161044a9190614d5a565b60405180910390f35b34801561045f57600080fd5b5061047a60048036038101906104759190614a81565b6117b0565b005b34801561048857600080fd5b50610491611ab7565b005b34801561049f57600080fd5b506104a8611b3f565b6040516104b692919061486f565b60405180910390f35b3480156104cb57600080fd5b506104e660048036038101906104e19190614842565b611bdf565b6040516104f39190614732565b60405180910390f35b34801561050857600080fd5b50610523600480360381019061051e9190614d75565b611bf7565b005b34801561053157600080fd5b5061053a611c8d565b60405161054791906147fb565b60405180910390f35b34801561055c57600080fd5b5061057760048036038101906105729190614842565b611cb7565b005b34801561058557600080fd5b506105a0600480360381019061059b9190614842565b611d3f565b6040516105ad91906148b3565b60405180910390f35b3480156105c257600080fd5b506105cb611dc5565b6040516105d89190614de9565b60405180910390f35b3480156105ed57600080fd5b5061060860048036038101906106039190614c63565b611deb565b005b34801561061657600080fd5b50610631600480360381019061062c9190614c63565b6122ca565b005b34801561063f57600080fd5b5061065a60048036038101906106559190614842565b6124e3565b604051610668929190614e04565b60405180910390f35b34801561067d57600080fd5b5061068661269e565b6040516106939190614732565b60405180910390f35b3480156106a857600080fd5b506106b1612720565b6040516106bf92919061486f565b60405180910390f35b3480156106d457600080fd5b506106dd6127c1565b6040516106ea9190614e4e565b60405180910390f35b3480156106ff57600080fd5b5061071a60048036038101906107159190614842565b6127e7565b005b34801561072857600080fd5b5061073161286f565b60405161073e9190614732565b60405180910390f35b34801561075357600080fd5b5061076e60048036038101906107699190614842565b612880565b005b34801561077c57600080fd5b5061079760048036038101906107929190614e69565b61296a565b6040516107a5929190614a4a565b60405180910390f35b3480156107ba57600080fd5b506107c3612a70565b6040516107d09190614732565b60405180910390f35b3480156107e557600080fd5b5061080060048036038101906107fb9190614842565b612a76565b005b60715481565b600061081e826074612b9190919063ffffffff16565b9050919050565b60008061083c836066612bab90919063ffffffff16565b9091508092508193505050915091565b607360009054906101000a900460ff1681565b7f000000000000000000000000a5b6194de99e6e3f693c02950b26c3201c21184973ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614156108ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e590614f2c565b60405180910390fd5b7f000000000000000000000000a5b6194de99e6e3f693c02950b26c3201c21184973ffffffffffffffffffffffffffffffffffffffff1661092d612c06565b73ffffffffffffffffffffffffffffffffffffffff1614610983576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097a90614fbe565b60405180910390fd5b61098c81612c5d565b6109e581600067ffffffffffffffff8111156109ab576109aa614adc565b5b6040519080825280601f01601f1916602001820160405280156109dd5781602001600182028036833780820191505090505b506000612cdc565b50565b6060803373ffffffffffffffffffffffffffffffffffffffff16606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614158015610a9757503373ffffffffffffffffffffffffffffffffffffffff16606d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b15610ad957336040517f79eaeb2b000000000000000000000000000000000000000000000000000000008152600401610ad091906147fb565b60405180910390fd5b60006066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b8152600401610b159190614fe5565b602060405180830381865af4158015610b32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b569190615015565b1415610b8e576040517f7818a60e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610c166070546066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b8152600401610bd09190614fe5565b602060405180830381865af4158015610bed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c119190615015565b612ead565b905060008167ffffffffffffffff811115610c3457610c33614adc565b5b604051908082528060200260200182016040528015610c625781602001602082028036833780820191505090505b50905060008267ffffffffffffffff811115610c8157610c80614adc565b5b604051908082528060200260200182016040528015610caf5781602001602082028036833780820191505090505b50905060006066731076d108448175dfcf0be58314bbfdb865d2f7ec630c8f298790916040518263ffffffff1660e01b8152600401610cee9190614fe5565b602060405180830381865af4158015610d0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2f9190615057565b905060005b8481108015610d44575060008814155b8015610d7d5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b1561117257610f0a610f04606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663acd201d0856040518263ffffffff1660e01b8152600401610de391906147fb565b602060405180830381865afa158015610e00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e249190615015565b606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630567847f606e60008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546040518263ffffffff1660e01b8152600401610ebe9190614732565b602060405180830381865afa158015610edb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eff9190615015565b612ead565b89612ead565b838281518110610f1d57610f1c615084565b5b60200260200101818152505081848281518110610f3d57610f3c615084565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828181518110610f8a57610f89615084565b5b602002602001015188610f9d91906150e2565b975061106082606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c494ec1e868581518110610ff457610ff3615084565b5b60200260200101516040518263ffffffff1660e01b81526004016110189190614732565b602060405180830381865afa158015611035573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110599190615015565b6000612ec6565b6110ab82606e60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546000612fb5565b607360009054906101000a900460ff1615611142576066731076d108448175dfcf0be58314bbfdb865d2f7ec630c8f298790916040518263ffffffff1660e01b81526004016110fa9190614fe5565b602060405180830381865af4158015611117573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113b9190615057565b915061115f565b611156826066612bab90919063ffffffff16565b90915050809250505b808061116a90615116565b915050610d34565b600088146111ac576040517f2e6c1bf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff8111156111c6576111c5614adc565b5b6040519080825280602002602001820160405280156111f45781602001602082028036833780820191505090505b5096508067ffffffffffffffff81111561121157611210614adc565b5b60405190808252806020026020018201604052801561123f5781602001602082028036833780820191505090505b50955060005b81811015611302578481815181106112605761125f615084565b5b602002602001015188828151811061127b5761127a615084565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508381815181106112c8576112c7615084565b5b60200260200101518782815181106112e3576112e2615084565b5b60200260200101818152505080806112fa90615116565b915050611245565b505050505050915091565b606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060019054906101000a900460ff1661135b5760008054906101000a900460ff1615611364565b611363613269565b5b6113a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161139a906151d1565b60405180910390fd5b60008060019054906101000a900460ff1615905080156113f3576001600060016101000a81548160ff02191690831515021790555060016000806101000a81548160ff0219169083151502179055505b6113fc8361327a565b61140582613340565b6008606f819055506008607081905550600a6072819055506001607360006101000a81548160ff0219169083151502179055507fb930683f0749189780c4016ec37d019eb0cbbf6550ce7374fac5cfbae93909a7607360009054906101000a900460ff1660405161147691906148b3565b60405180910390a1801561149f5760008060016101000a81548160ff0219169083151502179055505b505050565b7f000000000000000000000000a5b6194de99e6e3f693c02950b26c3201c21184973ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff161415611533576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161152a90614f2c565b60405180910390fd5b7f000000000000000000000000a5b6194de99e6e3f693c02950b26c3201c21184973ffffffffffffffffffffffffffffffffffffffff16611572612c06565b73ffffffffffffffffffffffffffffffffffffffff16146115c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115bf90614fbe565b60405180910390fd5b6115d182612c5d565b6115dd82826001612cdc565b5050565b606f5481565b6115fb83607461339b90919063ffffffff16565b611631576040517f0a1f2c0e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6066731076d108448175dfcf0be58314bbfdb865d2f7ec63cab455ae909185606e60008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205486866040518663ffffffff1660e01b81526004016116b295949392919061520f565b60006040518083038186803b1580156116ca57600080fd5b505af41580156116de573d6000803e3d6000fd5b505050506116f68360746133cb90919063ffffffff16565b50600061170360746133fb565b141561176b576001607360006101000a81548160ff0219169083151502179055507fb930683f0749189780c4016ec37d019eb0cbbf6550ce7374fac5cfbae93909a7607360009054906101000a900460ff1660405161176291906148b3565b60405180910390a15b505050565b600080600080600180600080935093509350935090919293565b606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6066731076d108448175dfcf0be58314bbfdb865d2f7ec6302f130289091846040518363ffffffff1660e01b81526004016117ec929190615262565b602060405180830381865af4158015611809573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182d91906152b7565b61186e57816040517fdc1b434d00000000000000000000000000000000000000000000000000000000815260040161186591906147fb565b60405180910390fd5b6066731076d108448175dfcf0be58314bbfdb865d2f7ec6302f130289091836040518363ffffffff1660e01b81526004016118aa929190615262565b602060405180830381865af41580156118c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118eb91906152b7565b61192c57806040517f5a08158400000000000000000000000000000000000000000000000000000000815260040161192391906147fb565b60405180910390fd5b600080611938846124e3565b91509150818111611984578381836040517f8b0123bf00000000000000000000000000000000000000000000000000000000815260040161197b939291906152e4565b60405180910390fd5b600080611990856124e3565b915091508181106119dc578481836040517f845286390000000000000000000000000000000000000000000000000000000081526004016119d3939291906152e4565b60405180910390fd5b60006119fe85856119ed91906150e2565b83856119f991906150e2565b612ead565b9050611a0c87826000612ec6565b611a1886826001612ec6565b611a6387606e60008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546000612fb5565b611aae86606e60008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546001612fb5565b50505050505050565b611abf613410565b73ffffffffffffffffffffffffffffffffffffffff16611add611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614611b33576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b2a90615367565b60405180910390fd5b611b3d600061327a565b565b6000806066731076d108448175dfcf0be58314bbfdb865d2f7ec630c8f298790916040518263ffffffff1660e01b8152600401611b7c9190614fe5565b602060405180830381865af4158015611b99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bbd9190615057565b9150611bd3826066612bab90919063ffffffff16565b90915050809150509091565b606e6020528060005260406000206000915090505481565b611bff613410565b73ffffffffffffffffffffffffffffffffffffffff16611c1d611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614611c73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c6a90615367565b60405180910390fd5b82606f819055508160708190555080607281905550505050565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b611cbf613410565b73ffffffffffffffffffffffffffffffffffffffff16611cdd611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614611d33576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d2a90615367565b60405180910390fd5b611d3c81613418565b50565b60006066731076d108448175dfcf0be58314bbfdb865d2f7ec6302f130289091846040518363ffffffff1660e01b8152600401611d7d929190615262565b602060405180830381865af4158015611d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbe91906152b7565b9050919050565b606b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b611df3613410565b73ffffffffffffffffffffffffffffffffffffffff16611e11611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614611e67576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e5e90615367565b60405180910390fd5b606b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ac8f4425846040518263ffffffff1660e01b8152600401611ec291906147fb565b602060405180830381865afa158015611edf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0391906152b7565b611f4457826040517f10a7bc6b000000000000000000000000000000000000000000000000000000008152600401611f3b91906147fb565b60405180910390fd5b6066731076d108448175dfcf0be58314bbfdb865d2f7ec6302f130289091856040518363ffffffff1660e01b8152600401611f80929190615262565b602060405180830381865af4158015611f9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc191906152b7565b1561200357826040517fbd133eee000000000000000000000000000000000000000000000000000000008152600401611ffa91906147fb565b60405180910390fd5b600080606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c494ec1e606c60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663acd201d0886040518263ffffffff1660e01b815260040161209f91906147fb565b602060405180830381865afa1580156120bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e09190615015565b6040518263ffffffff1660e01b81526004016120fc9190614732565b602060405180830381865afa158015612119573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213d9190615015565b90506000811461220e576000606d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166356ab819f876040518263ffffffff1660e01b81526004016121a491906147fb565b606060405180830381865afa1580156121c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e59190615387565b505090506121f38282612ead565b826121fe91906150e2565b925061220c86846001612ec6565b505b6066731076d108448175dfcf0be58314bbfdb865d2f7ec632dedbbf09091878588886040518663ffffffff1660e01b815260040161225095949392919061520f565b60006040518083038186803b15801561226857600080fd5b505af415801561227c573d6000803e3d6000fd5b505050508473ffffffffffffffffffffffffffffffffffffffff167f0503b4748a47435f2432d46ef300e0e2dc47baa0e5f04bb3bd8a355ee1e1dbe660405160405180910390a25050505050565b6122d2613410565b73ffffffffffffffffffffffffffffffffffffffff166122f0611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614612346576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161233d90615367565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614806123ad5750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b806123e45750600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b1561241b576040517f0855380c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81606b60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080606d60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082606c60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505050565b60008060006066731076d108448175dfcf0be58314bbfdb865d2f7ec630c8f298790916040518263ffffffff1660e01b81526004016125229190614fe5565b602060405180830381865af415801561253f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125639190615057565b905060006066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b81526004016125a19190614fe5565b602060405180830381865af41580156125be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125e29190615015565b9050806071546125f29190615409565b93508173ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614156126555760008185612636919061543a565b60715461264391906150e2565b905080856126519190615494565b9450505b606e60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205492505050915091565b60006066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b81526004016126da9190614fe5565b602060405180830381865af41580156126f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061271b9190615015565b905090565b6000806066731076d108448175dfcf0be58314bbfdb865d2f7ec6349923bff90916040518263ffffffff1660e01b815260040161275d9190614fe5565b602060405180830381865af415801561277a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279e9190615057565b91506127b4826066612bab90919063ffffffff16565b9091509050809150509091565b606d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6127ef613410565b73ffffffffffffffffffffffffffffffffffffffff1661280d611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614612863576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161285a90615367565b60405180910390fd5b61286c816138e3565b50565b600061287b60746133fb565b905090565b606b60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ac8f4425826040518263ffffffff1660e01b81526004016128db91906147fb565b602060405180830381865afa1580156128f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291c91906152b7565b1561295e57806040517fe3bd013b00000000000000000000000000000000000000000000000000000000815260040161295591906147fb565b60405180910390fd5b61296781613418565b50565b6060803373ffffffffffffffffffffffffffffffffffffffff16606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614158015612a1957503373ffffffffffffffffffffffffffffffffffffffff16606d60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b15612a5b57336040517f79eaeb2b000000000000000000000000000000000000000000000000000000008152600401612a5291906147fb565b60405180910390fd5b612a6584846139d1565b915091509250929050565b60705481565b612a7e613410565b73ffffffffffffffffffffffffffffffffffffffff16612a9c611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614612af2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ae990615367565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612b62576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b599061555c565b60405180910390fd5b612b6b8161327a565b50565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000612ba08360000183614190565b60001c905092915050565b600080600080612bcc612bbd866141bb565b876141e290919063ffffffff16565b905080604001519350806040015115612bfe57612bec8160000151614208565b9250612bfb8160200151614208565b91505b509250925092565b6000612c347f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b614219565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b612c65613410565b73ffffffffffffffffffffffffffffffffffffffff16612c83611c8d565b73ffffffffffffffffffffffffffffffffffffffff1614612cd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cd090615367565b60405180910390fd5b50565b6000612ce6612c06565b9050612cf184614223565b600083511180612cfe5750815b15612d0f57612d0d84846142dc565b505b6000612d3d7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd914360001b614309565b90508060000160009054906101000a900460ff16612ea65760018160000160006101000a81548160ff021916908315150217905550612e098583604051602401612d8791906147fb565b6040516020818303038152906040527f3659cfe6000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506142dc565b5060008160000160006101000a81548160ff021916908315150217905550612e2f612c06565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614612e9c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e93906155ee565b60405180910390fd5b612ea585614313565b5b5050505050565b6000818310612ebc5781612ebe565b825b905092915050565b8015612f405781606e60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612f1b9190615494565b925050819055508160716000828254612f349190615494565b92505081905550612fb0565b81606e60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612f8f91906150e2565b925050819055508160716000828254612fa891906150e2565b925050819055505b505050565b612fc983607461339b90919063ffffffff16565b15612fd357613264565b60008082613062576066731076d108448175dfcf0be58314bbfdb865d2f7ec63a4aadfcc909187876072546040518563ffffffff1660e01b815260040161301d949392919061560e565b6040805180830381865af4158015613039573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061305d9190615653565b6130e5565b6066731076d108448175dfcf0be58314bbfdb865d2f7ec6399f68a39909187876072546040518563ffffffff1660e01b81526004016130a4949392919061560e565b6040805180830381865af41580156130c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130e49190615653565b5b915091508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158061319e575060016066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b815260040161315b9190614fe5565b602060405180830381865af4158015613178573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061319c9190615015565b145b1561321a576066731076d108448175dfcf0be58314bbfdb865d2f7ec63cab455ae9091878786866040518663ffffffff1660e01b81526004016131e595949392919061520f565b60006040518083038186803b1580156131fd57600080fd5b505af4158015613211573d6000803e3d6000fd5b50505050613261565b607360009054906101000a900460ff161561324b576000607360006101000a81548160ff0219169083151502179055505b61325f85607461436290919063ffffffff16565b505b50505b505050565b600061327430612b6e565b15905090565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081603360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600060019054906101000a900460ff1661338f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161338690615705565b60405180910390fd5b613398816138e3565b50565b60006133c3836000018373ffffffffffffffffffffffffffffffffffffffff1660001b614392565b905092915050565b60006133f3836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6143b5565b905092915050565b6000613409826000016144c9565b9050919050565b600033905090565b6066731076d108448175dfcf0be58314bbfdb865d2f7ec6302f130289091836040518363ffffffff1660e01b8152600401613454929190615262565b602060405180830381865af4158015613471573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349591906152b7565b6134d657806040517f1adbb1530000000000000000000000000000000000000000000000000000000081526004016134cd91906147fb565b60405180910390fd5b6066731076d108448175dfcf0be58314bbfdb865d2f7ec63281359299091836040518363ffffffff1660e01b8152600401613512929190615262565b60006040518083038186803b15801561352a57600080fd5b505af415801561353e573d6000803e3d6000fd5b505050506135568160746133cb90919063ffffffff16565b506000606e60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600081111561389c576135b082826000612ec6565b6000600167ffffffffffffffff8111156135cd576135cc614adc565b5b6040519080825280602002602001820160405280156135fb5781602001602082028036833780820191505090505b5090506000600167ffffffffffffffff81111561361b5761361a614adc565b5b6040519080825280602002602001820160405280156136495781602001602082028036833780820191505090505b509050838260008151811061366157613660615084565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630567847f846040518263ffffffff1660e01b81526004016136f69190614732565b602060405180830381865afa158015613713573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137379190615015565b8160008151811061374b5761374a615084565b5b602002602001018181525050600080613800606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630567847f876040518263ffffffff1660e01b81526004016137b89190614732565b602060405180830381865afa1580156137d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137f99190615015565b60006139d1565b91509150606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c4d4e40858486856040518563ffffffff1660e01b81526004016138659493929190615725565b600060405180830381600087803b15801561387f57600080fd5b505af1158015613893573d6000803e3d6000fd5b50505050505050505b8173ffffffffffffffffffffffffffffffffffffffff167fa78a88a551e130ce9732be17784bdff12f72ab4a2c833fb2dcb3ef0818956b0360405160405180910390a25050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561394a576040517fe99d5ac500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80606560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff167f60a0f5b9f9e81e98216071b85826681c796256fe3d1354ecb675580fba64fa6960405160405180910390a250565b60608060006066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b8152600401613a109190614fe5565b602060405180830381865af4158015613a2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a519190615015565b1415613a89576040517f7818a60e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613b11606f546066731076d108448175dfcf0be58314bbfdb865d2f7ec6365da149690916040518263ffffffff1660e01b8152600401613acb9190614fe5565b602060405180830381865af4158015613ae8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b0c9190615015565b612ead565b905060008167ffffffffffffffff811115613b2f57613b2e614adc565b5b604051908082528060200260200182016040528015613b5d5781602001602082028036833780820191505090505b50905060008267ffffffffffffffff811115613b7c57613b7b614adc565b5b604051908082528060200260200182016040528015613baa5781602001602082028036833780820191505090505b50905060006066731076d108448175dfcf0be58314bbfdb865d2f7ec6349923bff90916040518263ffffffff1660e01b8152600401613be99190614fe5565b602060405180830381865af4158015613c06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c2a9190615057565b905060005b8481108015613c3f575060008914155b8015613c785750600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15613ff3576000606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632c431058846040518263ffffffff1660e01b8152600401613cda91906147fb565b602060405180830381865afa158015613cf7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d1b9190615015565b90508873ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480613d575750600081145b15613d7f57613d70836066612bab90919063ffffffff16565b90915090508093505050613c2f565b613d89818b612ead565b848381518110613d9c57613d9b615084565b5b60200260200101818152505082858381518110613dbc57613dbb615084565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050838281518110613e0957613e08615084565b5b60200260200101518a613e1c91906150e2565b9950613edf83606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c494ec1e878681518110613e7357613e72615084565b5b60200260200101516040518263ffffffff1660e01b8152600401613e979190614732565b602060405180830381865afa158015613eb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ed89190615015565b6001612ec6565b613f2a83606e60008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546001612fb5565b607360009054906101000a900460ff1615613fc1576066731076d108448175dfcf0be58314bbfdb865d2f7ec6349923bff90916040518263ffffffff1660e01b8152600401613f799190614fe5565b602060405180830381865af4158015613f96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fba9190615057565b9250613fdf565b613fd5836066612bab90919063ffffffff16565b9091509050809350505b8180613fea90615116565b92505050613c2f565b6000891461402d576040517f2e6c1bf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff81111561404757614046614adc565b5b6040519080825280602002602001820160405280156140755781602001602082028036833780820191505090505b5096508067ffffffffffffffff81111561409257614091614adc565b5b6040519080825280602002602001820160405280156140c05781602001602082028036833780820191505090505b50955060005b81811015614183578481815181106140e1576140e0615084565b5b60200260200101518882815181106140fc576140fb615084565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505083818151811061414957614148615084565b5b602002602001015187828151811061416457614163615084565b5b602002602001018181525050808061417b90615116565b9150506140c6565b5050505050509250929050565b60008260000182815481106141a8576141a7615084565b5b9060005260206000200154905092915050565b600060608273ffffffffffffffffffffffffffffffffffffffff16901b60001b9050919050565b6141ea6146f0565b61420082846000016144da90919063ffffffff16565b905092915050565b600060608260001c901c9050919050565b6000819050919050565b61422c81614539565b61426b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401614262906157f8565b60405180910390fd5b806142987f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b614219565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b606061430183836040518060600160405280602781526020016159d16027913961454c565b905092915050565b6000819050919050565b61431c81614223565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b600061438a836000018373ffffffffffffffffffffffffffffffffffffffff1660001b614619565b905092915050565b600080836001016000848152602001908152602001600020541415905092915050565b600080836001016000848152602001908152602001600020549050600081146144bd5760006001826143e791906150e2565b90506000600186600001805490506143ff91906150e2565b905081811461446e5760008660000182815481106144205761441f615084565b5b906000526020600020015490508087600001848154811061444457614443615084565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b8560000180548061448257614481615818565b5b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506144c3565b60009150505b92915050565b600081600001805490509050919050565b6144e26146f0565b82600301600083815260200190815260200160002060405180606001604052908160008201548152602001600182015481526020016002820160009054906101000a900460ff161515151581525050905092915050565b600080823b905060008111915050919050565b606061455784614539565b614596576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161458d906158b9565b60405180910390fd5b6000808573ffffffffffffffffffffffffffffffffffffffff16856040516145be9190615953565b600060405180830381855af49150503d80600081146145f9576040519150601f19603f3d011682016040523d82523d6000602084013e6145fe565b606091505b509150915061460e828286614689565b925050509392505050565b60006146258383614392565b61467e578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050614683565b600090505b92915050565b60608315614699578290506146e9565b6000835111156146ac5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016146e091906159ae565b60405180910390fd5b9392505050565b604051806060016040528060008019168152602001600080191681526020016000151581525090565b6000819050919050565b61472c81614719565b82525050565b60006020820190506147476000830184614723565b92915050565b6000604051905090565b600080fd5b600080fd5b61476a81614719565b811461477557600080fd5b50565b60008135905061478781614761565b92915050565b6000602082840312156147a3576147a2614757565b5b60006147b184828501614778565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006147e5826147ba565b9050919050565b6147f5816147da565b82525050565b600060208201905061481060008301846147ec565b92915050565b61481f816147da565b811461482a57600080fd5b50565b60008135905061483c81614816565b92915050565b60006020828403121561485857614857614757565b5b60006148668482850161482d565b91505092915050565b600060408201905061488460008301856147ec565b61489160208301846147ec565b9392505050565b60008115159050919050565b6148ad81614898565b82525050565b60006020820190506148c860008301846148a4565b92915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b614903816147da565b82525050565b600061491583836148fa565b60208301905092915050565b6000602082019050919050565b6000614939826148ce565b61494381856148d9565b935061494e836148ea565b8060005b8381101561497f5781516149668882614909565b975061497183614921565b925050600181019050614952565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6149c181614719565b82525050565b60006149d383836149b8565b60208301905092915050565b6000602082019050919050565b60006149f78261498c565b614a018185614997565b9350614a0c836149a8565b8060005b83811015614a3d578151614a2488826149c7565b9750614a2f836149df565b925050600181019050614a10565b5085935050505092915050565b60006040820190508181036000830152614a64818561492e565b90508181036020830152614a7881846149ec565b90509392505050565b60008060408385031215614a9857614a97614757565b5b6000614aa68582860161482d565b9250506020614ab78582860161482d565b9150509250929050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b614b1482614acb565b810181811067ffffffffffffffff82111715614b3357614b32614adc565b5b80604052505050565b6000614b4661474d565b9050614b528282614b0b565b919050565b600067ffffffffffffffff821115614b7257614b71614adc565b5b614b7b82614acb565b9050602081019050919050565b82818337600083830152505050565b6000614baa614ba584614b57565b614b3c565b905082815260208101848484011115614bc657614bc5614ac6565b5b614bd1848285614b88565b509392505050565b600082601f830112614bee57614bed614ac1565b5b8135614bfe848260208601614b97565b91505092915050565b60008060408385031215614c1e57614c1d614757565b5b6000614c2c8582860161482d565b925050602083013567ffffffffffffffff811115614c4d57614c4c61475c565b5b614c5985828601614bd9565b9150509250929050565b600080600060608486031215614c7c57614c7b614757565b5b6000614c8a8682870161482d565b9350506020614c9b8682870161482d565b9250506040614cac8682870161482d565b9150509250925092565b6000608082019050614ccb6000830187614723565b614cd86020830186614723565b614ce56040830185614723565b614cf26060830184614723565b95945050505050565b6000819050919050565b6000614d20614d1b614d16846147ba565b614cfb565b6147ba565b9050919050565b6000614d3282614d05565b9050919050565b6000614d4482614d27565b9050919050565b614d5481614d39565b82525050565b6000602082019050614d6f6000830184614d4b565b92915050565b600080600060608486031215614d8e57614d8d614757565b5b6000614d9c86828701614778565b9350506020614dad86828701614778565b9250506040614dbe86828701614778565b9150509250925092565b6000614dd382614d27565b9050919050565b614de381614dc8565b82525050565b6000602082019050614dfe6000830184614dda565b92915050565b6000604082019050614e196000830185614723565b614e266020830184614723565b9392505050565b6000614e3882614d27565b9050919050565b614e4881614e2d565b82525050565b6000602082019050614e636000830184614e3f565b92915050565b60008060408385031215614e8057614e7f614757565b5b6000614e8e85828601614778565b9250506020614e9f8582860161482d565b9150509250929050565b600082825260208201905092915050565b7f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060008201527f64656c656761746563616c6c0000000000000000000000000000000000000000602082015250565b6000614f16602c83614ea9565b9150614f2182614eba565b604082019050919050565b60006020820190508181036000830152614f4581614f09565b9050919050565b7f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060008201527f6163746976652070726f78790000000000000000000000000000000000000000602082015250565b6000614fa8602c83614ea9565b9150614fb382614f4c565b604082019050919050565b60006020820190508181036000830152614fd781614f9b565b9050919050565b8082525050565b6000602082019050614ffa6000830184614fde565b92915050565b60008151905061500f81614761565b92915050565b60006020828403121561502b5761502a614757565b5b600061503984828501615000565b91505092915050565b60008151905061505181614816565b92915050565b60006020828403121561506d5761506c614757565b5b600061507b84828501615042565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006150ed82614719565b91506150f883614719565b92508282101561510b5761510a6150b3565b5b828203905092915050565b600061512182614719565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415615154576151536150b3565b5b600182019050919050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b60006151bb602e83614ea9565b91506151c68261515f565b604082019050919050565b600060208201905081810360008301526151ea816151ae565b9050919050565b6151fa816147da565b82525050565b61520981614719565b82525050565b600060a0820190506152246000830188614fde565b61523160208301876151f1565b61523e6040830186615200565b61524b60608301856151f1565b61525860808301846151f1565b9695505050505050565b60006040820190506152776000830185614fde565b61528460208301846151f1565b9392505050565b61529481614898565b811461529f57600080fd5b50565b6000815190506152b18161528b565b92915050565b6000602082840312156152cd576152cc614757565b5b60006152db848285016152a2565b91505092915050565b60006060820190506152f960008301866147ec565b6153066020830185614723565b6153136040830184614723565b949350505050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000615351602083614ea9565b915061535c8261531b565b602082019050919050565b6000602082019050818103600083015261538081615344565b9050919050565b6000806000606084860312156153a05761539f614757565b5b60006153ae86828701615000565b93505060206153bf86828701615000565b92505060406153d086828701615000565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061541482614719565b915061541f83614719565b92508261542f5761542e6153da565b5b828204905092915050565b600061544582614719565b915061545083614719565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615489576154886150b3565b5b828202905092915050565b600061549f82614719565b91506154aa83614719565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156154df576154de6150b3565b5b828201905092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000615546602683614ea9565b9150615551826154ea565b604082019050919050565b6000602082019050818103600083015261557581615539565b9050919050565b7f45524331393637557067726164653a207570677261646520627265616b73206660008201527f7572746865722075706772616465730000000000000000000000000000000000602082015250565b60006155d8602f83614ea9565b91506155e38261557c565b604082019050919050565b60006020820190508181036000830152615607816155cb565b9050919050565b60006080820190506156236000830187614fde565b61563060208301866151f1565b61563d6040830185615200565b61564a6060830184615200565b95945050505050565b6000806040838503121561566a57615669614757565b5b600061567885828601615042565b925050602061568985828601615042565b9150509250929050565b7f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960008201527f6e697469616c697a696e67000000000000000000000000000000000000000000602082015250565b60006156ef602b83614ea9565b91506156fa82615693565b604082019050919050565b6000602082019050818103600083015261571e816156e2565b9050919050565b6000608082019050818103600083015261573f818761492e565b90508181036020830152615753818661492e565b9050818103604083015261576781856149ec565b9050818103606083015261577b81846149ec565b905095945050505050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b60006157e2602d83614ea9565b91506157ed82615786565b604082019050919050565b60006020820190508181036000830152615811816157d5565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60008201527f6e74726163740000000000000000000000000000000000000000000000000000602082015250565b60006158a3602683614ea9565b91506158ae82615847565b604082019050919050565b600060208201905081810360008301526158d281615896565b9050919050565b600081519050919050565b600081905092915050565b60005b8381101561590d5780820151818401526020810190506158f2565b8381111561591c576000848401525b50505050565b600061592d826158d9565b61593781856158e4565b93506159478185602086016158ef565b80840191505092915050565b600061595f8284615922565b915081905092915050565b600081519050919050565b60006159808261596a565b61598a8185614ea9565b935061599a8185602086016158ef565b6159a381614acb565b840191505092915050565b600060208201905081810360008301526159c88184615975565b90509291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220a1703fc71954cbb1a1560d4385dc2ddecc730aa26a4d16d5f09db1ec2697648464736f6c634300080b0033