diff --git a/contracts/adapters/AuctionRebalanceExtension.sol b/contracts/adapters/AuctionRebalanceExtension.sol new file mode 100644 index 00000000..120119a4 --- /dev/null +++ b/contracts/adapters/AuctionRebalanceExtension.sol @@ -0,0 +1,197 @@ +/* + Copyright 2023 Index Coop + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache License, Version 2.0 +*/ + +pragma solidity 0.6.10; +pragma experimental "ABIEncoderV2"; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; + +import { AddressArrayUtils } from "../lib/AddressArrayUtils.sol"; +import { BaseExtension } from "../lib/BaseExtension.sol"; +import { IAuctionRebalanceModuleV1 } from "../interfaces/IAuctionRebalanceModuleV1.sol"; +import { IBaseManager } from "../interfaces/IBaseManager.sol"; +import { ISetToken } from "../interfaces/ISetToken.sol"; + +/** + * @title AuctionRebalanceExtension + * @author Index Coop + * + * @dev Extension contract for interacting with the AuctionRebalanceModuleV1. This contract acts as a pass-through and functions + * are only callable by operator. + */ +contract AuctionRebalanceExtension is BaseExtension { + using AddressArrayUtils for address[]; + using SafeMath for uint256; + + /* ============ Structs ============ */ + + struct AuctionExecutionParams { + uint256 targetUnit; // Target quantity of the component in Set, in precise units (10 ** 18). + string priceAdapterName; // Identifier for the price adapter to be used. + bytes priceAdapterConfigData; // Encoded data for configuring the chosen price adapter. + } + + /* ============ State Variables ============ */ + + ISetToken public setToken; + IAuctionRebalanceModuleV1 public auctionModule; // AuctionRebalanceModuleV1 + + /* ============ Constructor ============ */ + + constructor(IBaseManager _manager, IAuctionRebalanceModuleV1 _auctionModule) public BaseExtension(_manager) { + auctionModule = _auctionModule; + setToken = manager.setToken(); + } + + /* ============ External Functions ============ */ + + /** + * @dev OPERATOR ONLY: Checks that the old components array matches the current components array and then invokes the + * AuctionRebalanceModuleV1 startRebalance function. + * + * Refer to AuctionRebalanceModuleV1 for function specific restrictions. + * + * @param _quoteAsset ERC20 token used as the quote asset in auctions. + * @param _oldComponents Addresses of existing components in the SetToken. + * @param _newComponents Addresses of new components to be added. + * @param _newComponentsAuctionParams AuctionExecutionParams for new components, indexed corresponding to _newComponents. + * @param _oldComponentsAuctionParams AuctionExecutionParams for existing components, indexed corresponding to + * the current component positions. Set to 0 for components being removed. + * @param _shouldLockSetToken Indicates if the rebalance should lock the SetToken. + * @param _rebalanceDuration Duration of the rebalance in seconds. + * @param _positionMultiplier Position multiplier at the time target units were calculated. + */ + function startRebalance( + IERC20 _quoteAsset, + address[] memory _oldComponents, + address[] memory _newComponents, + AuctionExecutionParams[] memory _newComponentsAuctionParams, + AuctionExecutionParams[] memory _oldComponentsAuctionParams, + bool _shouldLockSetToken, + uint256 _rebalanceDuration, + uint256 _positionMultiplier + ) + external + onlyOperator + { + address[] memory currentComponents = setToken.getComponents(); + + require(currentComponents.length == _oldComponents.length, "Old components length must match the current components length."); + + for (uint256 i = 0; i < _oldComponents.length; i++) { + require(currentComponents[i] == _oldComponents[i], "Input old components array must match the current components array."); + } + + bytes memory callData = abi.encodeWithSelector( + IAuctionRebalanceModuleV1.startRebalance.selector, + setToken, + _quoteAsset, + _newComponents, + _newComponentsAuctionParams, + _oldComponentsAuctionParams, + _shouldLockSetToken, + _rebalanceDuration, + _positionMultiplier + ); + + invokeManager(address(auctionModule), callData); + } + + /** + * @dev OPERATOR ONLY: Unlocks SetToken via AuctionRebalanceModuleV1. + * Refer to AuctionRebalanceModuleV1 for function specific restrictions. + */ + function unlock() external onlyOperator { + bytes memory callData = abi.encodeWithSelector( + IAuctionRebalanceModuleV1.unlock.selector, + setToken + ); + + invokeManager(address(auctionModule), callData); + } + + /** + * @dev OPERATOR ONLY: Sets the target raise percentage for all components on AuctionRebalanceModuleV1. + * Refer to AuctionRebalanceModuleV1 for function specific restrictions. + * + * @param _raiseTargetPercentage Amount to raise all component's unit targets by (in precise units) + */ + function setRaiseTargetPercentage(uint256 _raiseTargetPercentage) external onlyOperator { + bytes memory callData = abi.encodeWithSelector( + IAuctionRebalanceModuleV1.setRaiseTargetPercentage.selector, + setToken, + _raiseTargetPercentage + ); + + invokeManager(address(auctionModule), callData); + } + + /** + * @dev OPERATOR ONLY: Updates the bidding permission status for a list of addresses on AuctionRebalanceModuleV1. + * Refer to AuctionRebalanceModuleV1 for function specific restrictions. + * + * @param _bidders An array of addresses whose bidding permission status is to be toggled. + * @param _statuses An array of booleans indicating the new bidding permission status for each corresponding address in `_bidders`. + */ + function setBidderStatus( + address[] memory _bidders, + bool[] memory _statuses + ) + external + onlyOperator + { + bytes memory callData = abi.encodeWithSelector( + IAuctionRebalanceModuleV1.setBidderStatus.selector, + setToken, + _bidders, + _statuses + ); + + invokeManager(address(auctionModule), callData); + } + + /** + * @dev OPERATOR ONLY: Sets whether anyone can bid on the AuctionRebalanceModuleV1. + * Refer to AuctionRebalanceModuleV1 for function specific restrictions. + * + * @param _status A boolean indicating if anyone can bid. + */ + function setAnyoneBid(bool _status) external onlyOperator { + bytes memory callData = abi.encodeWithSelector( + IAuctionRebalanceModuleV1.setAnyoneBid.selector, + setToken, + _status + ); + + invokeManager(address(auctionModule), callData); + } + + /** + * @dev OPERATOR ONLY: Initializes the AuctionRebalanceModuleV1. + * Refer to AuctionRebalanceModuleV1 for function specific restrictions. + */ + function initialize() external onlyOperator { + bytes memory callData = abi.encodeWithSelector( + IAuctionRebalanceModuleV1.initialize.selector, + setToken + ); + + invokeManager(address(auctionModule), callData); + } +} diff --git a/contracts/interfaces/IAuctionRebalanceModuleV1.sol b/contracts/interfaces/IAuctionRebalanceModuleV1.sol new file mode 100644 index 00000000..fc7a7507 --- /dev/null +++ b/contracts/interfaces/IAuctionRebalanceModuleV1.sol @@ -0,0 +1,68 @@ +/* + Copyright 2023 Index Coop + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache License, Version 2.0 +*/ +pragma solidity 0.6.10; +pragma experimental "ABIEncoderV2"; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ISetToken } from "./ISetToken.sol"; + +interface IAuctionRebalanceModuleV1 { + + struct AuctionExecutionParams { + uint256 targetUnit; + string priceAdapterName; + bytes priceAdapterConfigData; + } + + function startRebalance( + ISetToken _setToken, + IERC20 _quoteAsset, + address[] calldata _newComponents, + AuctionExecutionParams[] memory _newComponentsAuctionParams, + AuctionExecutionParams[] memory _oldComponentsAuctionParams, + bool _shouldLockSetToken, + uint256 _rebalanceDuration, + uint256 _initialPositionMultiplier + ) external; + + function bid( + ISetToken _setToken, + IERC20 _component, + uint256 _componentAmount, + uint256 _quoteAssetLimit + ) external; + + function raiseAssetTargets(ISetToken _setToken) external; + + function unlock(ISetToken _setToken) external; + + function setRaiseTargetPercentage( + ISetToken _setToken, + uint256 _raiseTargetPercentage + ) external; + + function setBidderStatus( + ISetToken _setToken, + address[] memory _bidders, + bool[] memory _statuses + ) external; + + function setAnyoneBid(ISetToken _setToken, bool _status) external; + + function initialize(ISetToken _setToken) external; +} diff --git a/external/abi/set/AuctionRebalanceModuleV1.json b/external/abi/set/AuctionRebalanceModuleV1.json new file mode 100644 index 00000000..68dcde0e --- /dev/null +++ b/external/abi/set/AuctionRebalanceModuleV1.json @@ -0,0 +1,926 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "AuctionRebalanceModuleV1", + "sourceName": "contracts/protocol/modules/v1/AuctionRebalanceModuleV1.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IController", + "name": "_controller", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract ISetToken", + "name": "setToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isAnyoneAllowedToBid", + "type": "bool" + } + ], + "name": "AnyoneBidUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract ISetToken", + "name": "setToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newPositionMultiplier", + "type": "uint256" + } + ], + "name": "AssetTargetsRaised", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract ISetToken", + "name": "setToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sendToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiveToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "bidder", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IAuctionPriceAdapterV1", + "name": "priceAdapter", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isSellAuction", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "netQuantitySentBySet", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "netQuantityReceivedBySet", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "protocolFee", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "setTotalSupply", + "type": "uint256" + } + ], + "name": "BidExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract ISetToken", + "name": "setToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "bidder", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isBidderAllowed", + "type": "bool" + } + ], + "name": "BidderStatusUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract ISetToken", + "name": "setToken", + "type": "address" + } + ], + "name": "LockedRebalanceEndedEarly", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract ISetToken", + "name": "setToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newRaiseTargetPercentage", + "type": "uint256" + } + ], + "name": "RaiseTargetPercentageUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract ISetToken", + "name": "setToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "quoteAsset", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isSetTokenLocked", + "type": "bool" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "rebalanceDuration", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "initialPositionMultiplier", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "componentsInvolved", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "targetUnit", + "type": "uint256" + }, + { + "internalType": "string", + "name": "priceAdapterName", + "type": "string" + }, + { + "internalType": "bytes", + "name": "priceAdapterConfigData", + "type": "bytes" + } + ], + "indexed": false, + "internalType": "struct AuctionRebalanceModuleV1.AuctionExecutionParams[]", + "name": "auctionParameters", + "type": "tuple[]" + } + ], + "name": "RebalanceStarted", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + } + ], + "name": "allTargetsMet", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "_component", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "_quoteAsset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_componentAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_quoteAssetLimit", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isSellAuction", + "type": "bool" + } + ], + "name": "bid", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + } + ], + "name": "canRaiseAssetTargets", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + } + ], + "name": "canUnlockEarly", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [], + "name": "controller", + "outputs": [ + { + "internalType": "contract IController", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "name": "executionInfo", + "outputs": [ + { + "internalType": "uint256", + "name": "targetUnit", + "type": "uint256" + }, + { + "internalType": "string", + "name": "priceAdapterName", + "type": "string" + }, + { + "internalType": "bytes", + "name": "priceAdapterConfigData", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + } + ], + "name": "getAllowedBidders", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "_component", + "type": "address" + } + ], + "name": "getAuctionSizeAndDirection", + "outputs": [ + { + "internalType": "bool", + "name": "isSellAuction", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "componentQuantity", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "_component", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "_quoteAsset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_componentQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_quoteQuantityLimit", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isSellAuction", + "type": "bool" + } + ], + "name": "getBidPreview", + "outputs": [ + { + "components": [ + { + "internalType": "contract ISetToken", + "name": "setToken", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "sendToken", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "receiveToken", + "type": "address" + }, + { + "internalType": "contract IAuctionPriceAdapterV1", + "name": "priceAdapter", + "type": "address" + }, + { + "internalType": "bytes", + "name": "priceAdapterConfigData", + "type": "bytes" + }, + { + "internalType": "bool", + "name": "isSellAuction", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "auctionQuantity", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "componentPrice", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quantitySentBySet", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "quantityReceivedBySet", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "preBidTokenSentBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "preBidTokenReceivedBalance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "setTotalSupply", + "type": "uint256" + } + ], + "internalType": "struct AuctionRebalanceModuleV1.BidInfo", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + } + ], + "name": "getQuoteAssetBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + } + ], + "name": "getRebalanceComponents", + "outputs": [ + { + "internalType": "address[]", + "name": "", + "type": "address[]" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_bidder", + "type": "address" + } + ], + "name": "isAllowedBidder", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + } + ], + "name": "isQuoteAssetExcessOrAtTarget", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + } + ], + "name": "isRebalanceDurationElapsed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "", + "type": "address" + } + ], + "name": "permissionInfo", + "outputs": [ + { + "internalType": "bool", + "name": "isAnyoneAllowedToBid", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + } + ], + "name": "raiseAssetTargets", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "", + "type": "address" + } + ], + "name": "rebalanceInfo", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "quoteAsset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "rebalanceStartTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rebalanceDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "positionMultiplier", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "raiseTargetPercentage", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [], + "name": "removeModule", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + }, + { + "internalType": "bool", + "name": "_status", + "type": "bool" + } + ], + "name": "setAnyoneBid", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + }, + { + "internalType": "address[]", + "name": "_bidders", + "type": "address[]" + }, + { + "internalType": "bool[]", + "name": "_statuses", + "type": "bool[]" + } + ], + "name": "setBidderStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_raiseTargetPercentage", + "type": "uint256" + } + ], + "name": "setRaiseTargetPercentage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "_quoteAsset", + "type": "address" + }, + { + "internalType": "address[]", + "name": "_newComponents", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "targetUnit", + "type": "uint256" + }, + { + "internalType": "string", + "name": "priceAdapterName", + "type": "string" + }, + { + "internalType": "bytes", + "name": "priceAdapterConfigData", + "type": "bytes" + } + ], + "internalType": "struct AuctionRebalanceModuleV1.AuctionExecutionParams[]", + "name": "_newComponentsAuctionParams", + "type": "tuple[]" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "targetUnit", + "type": "uint256" + }, + { + "internalType": "string", + "name": "priceAdapterName", + "type": "string" + }, + { + "internalType": "bytes", + "name": "priceAdapterConfigData", + "type": "bytes" + } + ], + "internalType": "struct AuctionRebalanceModuleV1.AuctionExecutionParams[]", + "name": "_oldComponentsAuctionParams", + "type": "tuple[]" + }, + { + "internalType": "bool", + "name": "_shouldLockSetToken", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "_rebalanceDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_initialPositionMultiplier", + "type": "uint256" + } + ], + "name": "startRebalance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "contract ISetToken", + "name": "_setToken", + "type": "address" + } + ], + "name": "unlock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function", + "gas": "0xa7d8c0" + } + ], + "bytecode": "0x60806040523480156200001157600080fd5b50604051620054033803806200540383398101604081905262000034916200005e565b600080546001600160a01b0319166001600160a01b0392909216919091179055600180556200008e565b60006020828403121562000070578081fd5b81516001600160a01b038116811462000087578182fd5b9392505050565b615365806200009e6000396000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c80638d50c6c1116100c3578063d4f005321161007c578063d4f0053214610304578063dc7bc58514610317578063dc8abe2e1461032a578063f47876981461034e578063f77c479114610361578063ff0932a11461037657610158565b80638d50c6c1146102855780638e0f7756146102a5578063b26faa0a146102b8578063c2098812146102cb578063c3824c48146102de578063c4d66de8146102f157610158565b8063421dec4d11610115578063421dec4d1461020257806345e3db3e14610224578063602ab35d146102375780636db4a26214610257578063737531ba1461026a578063847ef08d1461027d57610158565b80630b2c85eb1461015d57806323ab55ec14610187578063270e5590146101a75780632f6c493c146101c757806339a88f80146101dc57806341cefcd1146101ef575b600080fd5b61017061016b3660046143f8565b610389565b60405161017e92919061474f565b60405180910390f35b61019a6101953660046144dc565b6104db565b60405161017e9190615164565b6101ba6101b53660046142a3565b61051b565b60405161017e9190614744565b6101da6101d53660046142a3565b61052e565b005b6101ba6101ea3660046142a3565b610624565b6101ba6101fd3660046142a3565b61062f565b6102156102103660046143f8565b61063a565b60405161017e9392919061524a565b6101ba6102323660046142a3565b610777565b61024a6102453660046142a3565b61078c565b60405161017e9190614731565b6101da6102653660046144dc565b610810565b6101da61027836600461454b565b61091c565b6101da610981565b6102986102933660046142a3565b610a66565b60405161017e9190615241565b6101da6102b336600461440a565b610b00565b6101da6102c63660046142f7565b610e49565b6101ba6102d93660046142a3565b610fa9565b6101ba6102ec3660046142bf565b610fb4565b6101da6102ff3660046142a3565b610fd4565b61024a6103123660046142a3565b6111e1565b6101ba6103253660046142a3565b611263565b61033d6103383660046142a3565b61126e565b60405161017e959493929190614825565b6101da61035c3660046143cb565b6112a8565b610369611306565b60405161017e919061462c565b6101da6103843660046142a3565b611315565b600080836103968161141c565b6104298460046000886001600160a01b03166001600160a01b0316815260200190815260200160002060050180548060200260200160405190810160405280929190818152602001828054801561041657602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116103f8575b505050505061144490919063ffffffff16565b61044e5760405162461bcd60e51b815260040161044590614d43565b60405180910390fd5b6000856001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561048957600080fd5b505afa15801561049d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c19190614576565b90506104ce86868361145c565b9350935050509250929050565b6104e3613c27565b866104ed8161141c565b6104f988888888611583565b610501613c27565b61050e898988888861171b565b9998505050505050505050565b600061052682611b4f565b90505b919050565b600061053982611baf565b9050600061054683611bec565b905081806105515750805b61056d5760405162461bcd60e51b8152600401610445906148bf565b80156105b8576001600160a01b038316600081815260046020526040808220600201829055517f7ebe07e0f6679ed2dd131ed9d9498112c84991ccae90b0568240bf0dbf680d5c9190a25b6001600160a01b03831660008181526004602081905260408083208201839055805163a69df4b560e01b8152905163a69df4b59382840193909282900301818387803b15801561060757600080fd5b505af115801561061b573d6000803e3d6000fd5b50505050505050565b600061052682611bec565b600061052682611c2f565b600260208181526000938452604080852082529284529282902080546001808301805486519281161561010002600019011694909404601f8101879004870282018701909552848152909491939092918301828280156106db5780601f106106b0576101008083540402835291602001916106db565b820191906000526020600020905b8154815290600101906020018083116106be57829003601f168201915b50505060028085018054604080516020601f600019610100600187161502019094169590950492830185900485028101850190915281815295969594509092509083018282801561076d5780601f106107425761010080835404028352916020019161076d565b820191906000526020600020905b81548152906001019060200180831161075057829003601f168201915b5050505050905083565b60036020526000908152604090205460ff1681565b6060816107988161141c565b6001600160a01b0383166000908152600360209081526040918290206001018054835181840281018401909452808452909183018282801561080357602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116107e5575b5050505050915050919050565b600260015414156108335760405162461bcd60e51b815260040161044590615109565b60026001558561084281611ccd565b61084e87878787611583565b610856613c27565b610863888887878761171b565b905061086e81611cf3565b600061087982611d36565b905060008061088784611de9565b9150915083604001516001600160a01b031684602001516001600160a01b031685600001516001600160a01b03167f96310ab47353685e74601a419fddb52db22b6ce0f72cb735c35ff494289dd6423388606001518960a001518a60e0015189898c8e6101800151604051610903989796959493929190614640565b60405180910390a4505060018055505050505050505050565b8161092681611e9e565b6001600160a01b03831660008181526004602081905260409182902001849055517f6a1e9ac0e71aa1dc7854a57bce846b04b1aae20dc994b832098200d9236d1d4a90610974908590615241565b60405180910390a2505050565b336000908152600360205260408120905b60018201548110156109f15760008260020160008460010184815481106109b557fe5b6000918252602080832091909101546001600160a01b031683528201929092526040019020805460ff1916911515919091179055600101610992565b50336000908152600460208190526040822080546001600160a01b031916815560018101839055600281018390556003810183905590810182905590610a3a6005830182613cb5565b5050336000908152600360205260408120805460ff1916815590610a616001830182613cb5565b505050565b6001600160a01b038082166000908152600460208190526040808320805491516370a0823160e01b8152939490939116916370a0823191610aa99187910161462c565b60206040518083038186803b158015610ac157600080fd5b505afa158015610ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af99190614576565b9392505050565b88610b0a81611e9e565b838015610b995750306001600160a01b03168a6001600160a01b031663d7b96d4e6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b5557600080fd5b505afa158015610b69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8d919061409b565b6001600160a01b031614155b15610bf257896001600160a01b031663f83d08ba6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610bd957600080fd5b505af1158015610bed573d6000803e3d6000fd5b505050505b606080610c768c6001600160a01b03166399d50d5d6040518163ffffffff1660e01b815260040160006040518083038186803b158015610c3157600080fd5b505afa158015610c45573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c6d91908101906140b7565b8b8b8b8b611ec4565b909250905060005b8251811015610d8f57610cb6838281518110610c9657fe5b60200260200101518e6001600160a01b0316611f8d90919063ffffffff16565b15610cd35760405162461bcd60e51b815260040161044590614e5c565b818181518110610cdf57fe5b6020026020010151600260008f6001600160a01b03166001600160a01b031681526020019081526020016000206000858481518110610d1a57fe5b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600082015181600001556020820151816001019080519060200190610d68929190613cd3565b5060408201518051610d84916002840191602090910190613cd3565b505050600101610c7e565b506001600160a01b038c8116600090815260046020908152604090912080546001600160a01b031916928e1692909217825542600183015560028201879055600382018690558351610de79260050191850190613d4d565b508a6001600160a01b03168c6001600160a01b03167f2ca831858de887d2ca1c692d1940334f1d3f6c80c9101a306201d66397cf9be68888888787604051610e3395949392919061475f565b60405180910390a3505050505050505050505050565b82610e5381611e9e565b610e63838363ffffffff61201916565b60005b8351811015610fa257610ea085858381518110610e7f57fe5b6020026020010151858481518110610e9357fe5b6020026020010151612047565b828181518110610eac57fe5b602002602001015160036000876001600160a01b03166001600160a01b031681526020019081526020016000206002016000868481518110610eea57fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550838181518110610f3557fe5b60200260200101516001600160a01b0316856001600160a01b03167f4e771e3486d7afcce48115112ca75bc21bc33ac6d6261f7d273b9c5820606717858481518110610f7d57fe5b6020026020010151604051610f929190614744565b60405180910390a3600101610e66565b5050505050565b600061052682611baf565b600082610fc08161141c565b610fca84846121f7565b91505b5092915050565b8033610fe08282612241565b82610fea81612267565b6060846001600160a01b031663802758606040518163ffffffff1660e01b815260040160006040518083038186803b15801561102557600080fd5b505afa158015611039573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110619190810190614153565b905060005b81518110156110f457611077613dae565b82828151811061108357fe5b60200260200101519050806060015160ff166000146110b45760405162461bcd60e51b815260040161044590614e5c565b6110c18160400151612328565b6001600160a01b038089166000908152600260209081526040808320955190931682529390935290912055600101611066565b5061116e856001600160a01b0316635230c3966040518163ffffffff1660e01b815260040160206040518083038186803b15801561113157600080fd5b505afa158015611145573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111699190614576565b612328565b6001600160a01b03861660008181526004602081905260408083206003019490945583516307ff078f60e11b815293519293630ffe0f1e938183019392909182900301818387803b1580156111c257600080fd5b505af11580156111d6573d6000803e3d6000fd5b505050505050505050565b6060816111ed8161141c565b6001600160a01b03831660009081526004602090815260409182902060050180548351818402810184019094528084529091830182828015610803576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116107e5575050505050915050919050565b60006105268261234e565b6004602081905260009182526040909120805460018201546002830154600384015493909401546001600160a01b03909216939092909185565b816112b281611e9e565b6001600160a01b03831660008181526003602052604090819020805460ff1916851515179055517f1fed19c0eee5ddf8ef482a13e2f0c3ec5c1390b1e39160fe52eabd651ecc7dba90610974908590614744565b6000546001600160a01b031681565b8061131f81611ccd565b61132882611baf565b156113455760405162461bcd60e51b815260040161044590614bec565b61134e82611b4f565b61136a5760405162461bcd60e51b815260040161044590614b2b565b6001600160a01b0382166000908152600460208190526040822001546113ca906113a29061139661240d565b9063ffffffff61241a16565b6001600160a01b0385166000908152600460205260409020600301549063ffffffff61243f16565b6001600160a01b0384166000818152600460205260409081902060030183905551919250907fe4c448aaaad94925b669914540bde1ea0123c0b2320e4cf6ea0ad7a1818a1c9890610974908490615241565b61142581612469565b6114415760405162461bcd60e51b8152600401610445906149c2565b50565b600080611451848461256d565b925050505b92915050565b6000805460405163792aa04f60e01b8152829182916001600160a01b039091169063792aa04f9061149390309085906004016146f1565b60206040518083038186803b1580156114ab57600080fd5b505afa1580156114bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e39190614576565b90506000806000806114f68a8a8a6125d3565b93509350935093508284141561151e5760405162461bcd60e51b815260040161044590614eca565b8181109650866115645761155f6115438661153761240d565b9063ffffffff61262e16565b611553838563ffffffff61262e16565b9063ffffffff61243f16565b611574565b611574828263ffffffff61262e16565b95505050505050935093915050565b6001600160a01b0380851660009081526004602052604090205481169084168114156115c15760405162461bcd60e51b815260040161044590614a38565b806001600160a01b0316836001600160a01b0316146115f25760405162461bcd60e51b815260040161044590614a0a565b6116838460046000886001600160a01b03166001600160a01b03168152602001908152602001600020600501805480602002602001604051908101604052809291908181526020018280548015610416576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116103f857505050505061144490919063ffffffff16565b61169f5760405162461bcd60e51b815260040161044590614d43565b6116b86001600160a01b0386168563ffffffff611f8d16565b156116d55760405162461bcd60e51b815260040161044590614e5c565b6116de85611baf565b156116fb5760405162461bcd60e51b815260040161044590614bec565b60008211610fa25760405162461bcd60e51b815260040161044590614888565b611723613c27565b6001600160a01b038616808252604080516318160ddd60e01b815290516318160ddd91600480820192602092909190829003018186803b15801561176657600080fd5b505afa15801561177a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179e9190614576565b6101808201526117ae8686612670565b6001600160a01b0390811660608301528681166000908152600260208181526040808420948a168452938152918390208101805484516001821615610100026000190190911692909204601f8101849004840283018401909452838252909290918301828280156118605780601f1061183557610100808354040283529160200191611860565b820191906000526020600020905b81548152906001019060200180831161184357829003601f168201915b5050505050816080018190525061187d868683610180015161145c565b60c0830152151560a08201819052821515146118ab5760405162461bcd60e51b815260040161044590614c94565b6000198414156118c1578060c0015193506118e5565b8060c001518411156118e55760405162461bcd60e51b815260040161044590614ab3565b6118f48160a001518787612727565b6001600160a01b039081166040808501919091529181166020808501919091526060840151898316600090815260049092529290206001015491169063104b9b649088908890889061194d90429063ffffffff61262e16565b6001600160a01b038c166000908152600460208190526040918290206002015460808a015192516001600160e01b031960e08a901b16815261199597969594939192016146a8565b60206040518083038186803b1580156119ad57600080fd5b505afa1580156119c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e59190614576565b60e0820181905260a0820151600091611a009190879061277a565b60208301516040516370a0823160e01b81529192506001600160a01b0316906370a0823190611a33908a9060040161462c565b60206040518083038186803b158015611a4b57600080fd5b505afa158015611a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a839190614576565b61014083015260408083015190516370a0823160e01b81526001600160a01b03909116906370a0823190611abb908a9060040161462c565b60206040518083038186803b158015611ad357600080fd5b505afa158015611ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0b9190614576565b82610160018181525050611b2a8260a0015182868561014001516127a6565b611b398260a001518683612817565b6101208401526101008301525095945050505050565b6001600160a01b0380821660009081526004602052604081208054919290918391611b7c91869116612830565b8254611b929086906001600160a01b03166128cf565b119050611b9e8461234e565b8015611ba75750805b949350505050565b6001600160a01b0381166000908152600460205260408120600281015460018201544291611be3919063ffffffff61241a16565b11159392505050565b6001600160a01b0381166000908152600460205260408120611c0d8361234e565b8015611c1d5750611c1d83611c2f565b8015610af95750600401541592915050565b6001600160a01b0380821660009081526004602052604081208054919290918391611c5c91869116612830565b8254611c729086906001600160a01b03166128cf565b835491109150600090611cb990611c939087906001600160a01b0316612830565b8454600190611cac9089906001600160a01b03166128cf565b919063ffffffff61291816565b90508180611cc45750805b95945050505050565b611cd781336121f7565b6114415760405162461bcd60e51b815260040161044590614de4565b611d0c816040015133836000015184610120015161294f565b60208101516101008201518251611441926001600160a01b0390911691339063ffffffff61295b16565b604080820151825161016084015192516370a0823160e01b81526000938491611dc991906001600160a01b038616906370a0823190611d7990879060040161462c565b60206040518083038186803b158015611d9157600080fd5b505afa158015611da5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115379190614576565b90506000611dd8600083612aa5565b9050611cc483876040015183612b3a565b80516020820151610180830151610140840151600093849390928492611e21926001600160a01b03861692909163ffffffff612be116565b505090506000611e558660400151876101800151886101600151866001600160a01b0316612be1909392919063ffffffff16565b505090506000611e738388610140015161262e90919063ffffffff16565b90506000611e8f8861016001518461262e90919063ffffffff16565b91965090945050505050915091565b611ea88133612cd2565b61141c5760405162461bcd60e51b815260040161044590615088565b815160609081908514611ee95760405162461bcd60e51b815260040161044590614ba3565b8251875114611f0a5760405162461bcd60e51b815260040161044590614fb4565b611f4f8686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b9392505063ffffffff612d60169050565b9150611f5a82612e52565b15611f775760405162461bcd60e51b815260040161044590614853565b611f818385612f01565b90509550959350505050565b600080836001600160a01b031663a7bdad03846040518263ffffffff1660e01b8152600401611fbc919061462c565b60006040518083038186803b158015611fd457600080fd5b505afa158015611fe8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261201091908101906140b7565b51119392505050565b805182511461203a5760405162461bcd60e51b815260040161044590614993565b61204382613049565b5050565b8080156120e257506120e08260036000866001600160a01b03166001600160a01b03168152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610416576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116103f857505050505061144490919063ffffffff16565b155b1561212d576001600160a01b0383811660009081526003602090815260408220600190810180549182018155835291200180546001600160a01b031916918416919091179055610a61565b801580156121c757506121c78260036000866001600160a01b03166001600160a01b03168152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610416576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116103f857505050505061144490919063ffffffff16565b15610a61576001600160a01b0383166000908152600360205260409020610a61906001018363ffffffff61309016565b6001600160a01b0382166000908152600360205260408120805460ff1680610fca57506001600160a01b038316600090815260028201602052604090205460ff1691505092915050565b61224b8282612cd2565b6120435760405162461bcd60e51b815260040161044590615088565b600054604051631d3af8fb60e21b81526001600160a01b03909116906374ebe3ec9061229790849060040161462c565b60206040518083038186803b1580156122af57600080fd5b505afa1580156122c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e79190614254565b6123035760405162461bcd60e51b815260040161044590615045565b61230c816131bc565b6114415760405162461bcd60e51b815260040161044590614af4565b60008082121561234a5760405162461bcd60e51b815260040161044590614d7a565b5090565b6001600160a01b038116600090815260046020908152604080832060050180548251818502810185019093528083526060938301828280156123b957602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161239b575b50939450600093505050505b8151811015612403576123eb848383815181106123de57fe5b60200260200101516131eb565b156123fb57600092505050610529565b6001016123c5565b5060019392505050565b670de0b6b3a76400005b90565b600082820183811015610af95760405162461bcd60e51b815260040161044590614a7c565b6000610af98261245d85670de0b6b3a764000063ffffffff61326316565b9063ffffffff61329d16565b60008054604051631d3af8fb60e21b81526001600160a01b03909116906374ebe3ec9061249a90859060040161462c565b60206040518083038186803b1580156124b257600080fd5b505afa1580156124c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ea9190614254565b801561052657506040516335fc6c9f60e21b81526001600160a01b0383169063d7f1b27c9061251d90309060040161462c565b60206040518083038186803b15801561253557600080fd5b505afa158015612549573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105269190614254565b81516000908190815b818110156125c057846001600160a01b031686828151811061259457fe5b60200260200101516001600160a01b031614156125b8579250600191506125cc9050565b600101612576565b50600019600092509250505b9250929050565b60008060008060006125e588886128cf565b905060006125f38989612830565b90506000612607888463ffffffff6132df16565b9050600061261b898463ffffffff6132f116565b939b929a50909850919650945050505050565b6000610af983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613330565b6001600160a01b03828116600090815260026020818152604080842094861684529381528383206001908101805486519281161561010002600019011693909304601f81018390048302820183019095528481529293610af993929183018282801561271d5780601f106126f25761010080835404028352916020019161271d565b820191906000526020600020905b81548152906001019060200180831161270057829003601f168201915b505050505061335c565b60008084612750576001600160a01b03808516600090815260046020526040902054168361276e565b6001600160a01b038085166000908152600460205260409020548491165b91509150935093915050565b60008361279657612791838363ffffffff61337316565b611ba7565b611ba7838363ffffffff6132f116565b83156127d157818311156127cc5760405162461bcd60e51b815260040161044590614c23565b612811565b818310156127f15760405162461bcd60e51b815260040161044590614b6e565b808311156128115760405162461bcd60e51b815260040161044590614daf565b50505050565b6000808461282657828461276e565b5091939092509050565b6000610af960046000856001600160a01b03166001600160a01b031681526020019081526020016000206003015461245d61289d866001600160a01b0316635230c3966040518163ffffffff1660e01b815260040160206040518083038186803b15801561113157600080fd5b6001600160a01b038088166000908152600260209081526040808320938a16835292905220549063ffffffff61326316565b6000610af9836001600160a01b03166366cb8d2f846040518263ffffffff1660e01b8152600401612900919061462c565b60206040518083038186803b15801561113157600080fd5b600061292a838363ffffffff61241a16565b8411158015611ba75750612944838363ffffffff61262e16565b909310159392505050565b61281184848484613391565b8015612811576040516370a0823160e01b81526000906001600160a01b038516906370a082319061299090889060040161462c565b60206040518083038186803b1580156129a857600080fd5b505afa1580156129bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e09190614576565b90506129ee858585856134b5565b6040516370a0823160e01b81526000906001600160a01b038616906370a0823190612a1d90899060040161462c565b60206040518083038186803b158015612a3557600080fd5b505afa158015612a49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6d9190614576565b9050612a7f828463ffffffff61262e16565b8114612a9d5760405162461bcd60e51b815260040161044590614e93565b505050505050565b6000805460405163792aa04f60e01b815282916001600160a01b03169063792aa04f90612ad890309088906004016146f1565b60206040518083038186803b158015612af057600080fd5b505afa158015612b04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b289190614576565b9050610fca838263ffffffff61337316565b8015610a6157610a61826000809054906101000a90046001600160a01b03166001600160a01b031663469048406040518163ffffffff1660e01b815260040160206040518083038186803b158015612b9157600080fd5b505afa158015612ba5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc9919061409b565b6001600160a01b03861691908463ffffffff61295b16565b600080600080866001600160a01b03166370a08231896040518263ffffffff1660e01b8152600401612c13919061462c565b60206040518083038186803b158015612c2b57600080fd5b505afa158015612c3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c639190614576565b90506000612c96896001600160a01b03166366cb8d2f8a6040518263ffffffff1660e01b8152600401612900919061462c565b905060008215612cb357612cac888885856135bf565b9050612cb7565b5060005b612cc28a8a83613602565b9199909850909650945050505050565b6000816001600160a01b0316836001600160a01b031663481c6a756040518163ffffffff1660e01b815260040160206040518083038186803b158015612d1757600080fd5b505afa158015612d2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d4f919061409b565b6001600160a01b0316149392505050565b81518151606091908281830167ffffffffffffffff81118015612d8257600080fd5b50604051908082528060200260200182016040528015612dac578160200160208202803683370190505b50905060005b83811015612dfa57868181518110612dc657fe5b6020026020010151828281518110612dda57fe5b6001600160a01b0390921660209283029190910190910152600101612db2565b5060005b82811015612e4857858181518110612e1257fe5b60200260200101518282860181518110612e2857fe5b6001600160a01b0390921660209283029190910190910152600101612dfe565b5095945050505050565b600080825111612e745760405162461bcd60e51b815260040161044590615140565b60005b6001835103811015612ef8576000838281518110612e9157fe5b6020026020010151905060008260010190505b8451811015612eee57848181518110612eb957fe5b60200260200101516001600160a01b0316826001600160a01b03161415612ee65760019350505050610529565b600101612ea4565b5050600101612e77565b50600092915050565b815181516060919080820167ffffffffffffffff81118015612f2257600080fd5b50604051908082528060200260200182016040528015612f5c57816020015b612f49613df2565b815260200190600190039081612f415790505b50925060005b82811015612fb957612f86868281518110612f7957fe5b6020026020010151613780565b858181518110612f9257fe5b6020026020010151848281518110612fa657fe5b6020908102919091010152600101612f62565b5060005b81811015613040576000858281518110612fd357fe5b60200260200101516000015111612ffc5760405162461bcd60e51b815260040161044590614f2d565b61300b858281518110612f7957fe5b84818151811061301757fe5b6020026020010151848285018151811061302d57fe5b6020908102919091010152600101612fbd565b50505092915050565b600081511161306a5760405162461bcd60e51b815260040161044590614f7d565b61307381612e52565b156114415760405162461bcd60e51b815260040161044590614ccb565b6000806130f6848054806020026020016040519081016040528092919081815260200182805480156130eb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116130cd575b50505050508461256d565b91509150806131175760405162461bcd60e51b815260040161044590614935565b8354600019018281146131895784818154811061313057fe5b9060005260206000200160009054906101000a90046001600160a01b031685848154811061315a57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b8480548061319357fe5b600082815260209020810160001990810180546001600160a01b03191690550190555050505050565b6040516353bae5f760e01b81526000906001600160a01b038316906353bae5f79061251d90309060040161462c565b6001600160a01b0380831660009081526004602052604081205490918381169116141561321a57506000611456565b60006132268484612830565b9050600061323485856128cf565b9050600082116132475780821415611451565b6132598282600163ffffffff61291816565b1595945050505050565b60008261327257506000611456565b8282028284828161327f57fe5b0414610af95760405162461bcd60e51b815260040161044590614e1b565b6000610af983836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061382d565b6000610af9838363ffffffff61337316565b60008215806132fe575081155b1561330b57506000611456565b610af96001611396670de0b6b3a764000061245d83611537898963ffffffff61326316565b600081848411156133545760405162461bcd60e51b81526004016104459190614812565b505050900390565b60008061336883613864565b9050610af98161386f565b6000610af9670de0b6b3a764000061245d858563ffffffff61326316565b8015612811576040516370a0823160e01b81526000906001600160a01b038616906370a08231906133c690869060040161462c565b60206040518083038186803b1580156133de57600080fd5b505afa1580156133f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134169190614576565b90506134248585858561392c565b6040516370a0823160e01b81526000906001600160a01b038716906370a082319061345390879060040161462c565b60206040518083038186803b15801561346b57600080fd5b505afa15801561347f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a39190614576565b9050612a7f828463ffffffff61241a16565b801561281157606082826040516024016134d09291906146f1565b60408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b179052516347b7819960e11b81529091506060906001600160a01b03871690638f6f03329061352f908890600090879060040161470a565b600060405180830381600087803b15801561354957600080fd5b505af115801561355d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135859190810190614270565b805190915015612a9d57808060200190518101906135a39190614254565b612a9d5760405162461bcd60e51b815260040161044590614964565b6000806135e26135d5848863ffffffff61337316565b869063ffffffff61262e16565b90506135f886611553868463ffffffff61262e16565b9695505050505050565b600061360e8484613984565b90508015801561361e5750600082115b156136955761362d8484611f8d565b613690576040516304e3532760e41b81526001600160a01b03851690634e3532709061365d90869060040161462c565b600060405180830381600087803b15801561367757600080fd5b505af115801561368b573d6000803e3d6000fd5b505050505b613712565b8080156136a0575081155b15613712576136af8484611f8d565b61371257604051636f86c89760e01b81526001600160a01b03851690636f86c897906136df90869060040161462c565b600060405180830381600087803b1580156136f957600080fd5b505af115801561370d573d6000803e3d6000fd5b505050505b836001600160a01b0316632ba57d178461372b85613a0b565b6040518363ffffffff1660e01b81526004016137489291906146f1565b600060405180830381600087803b15801561376257600080fd5b505af1158015613776573d6000803e3d6000fd5b5050505050505050565b600061378f826020015161335c565b60408084015190516301e7dafd60e21b81529192506001600160a01b0383169163079f6bf4916137c191600401614812565b60206040518083038186803b1580156137d957600080fd5b505afa1580156137ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138119190614254565b6120435760405162461bcd60e51b815260040161044590614d02565b6000818361384e5760405162461bcd60e51b81526004016104459190614812565b50600083858161385a57fe5b0495945050505050565b805160209091012090565b600080548190613887906001600160a01b0316613a30565b6001600160a01b031663e6d642c530856040518363ffffffff1660e01b81526004016138b49291906146f1565b60206040518083038186803b1580156138cc57600080fd5b505afa1580156138e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613904919061409b565b90506001600160a01b0381166105265760405162461bcd60e51b815260040161044590614c65565b612811846323b872dd60e01b85858560405160240161394d93929190614684565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613aaf565b600080836001600160a01b03166366cb8d2f846040518263ffffffff1660e01b81526004016139b3919061462c565b60206040518083038186803b1580156139cb57600080fd5b505afa1580156139df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a039190614576565b139392505050565b6000600160ff1b821061234a5760405162461bcd60e51b815260040161044590614ffd565b6040516373b2e76b60e11b81526000906001600160a01b0383169063e765ced690613a5f908490600401615241565b60206040518083038186803b158015613a7757600080fd5b505afa158015613a8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610526919061409b565b6060613b04826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613b3e9092919063ffffffff16565b805190915015610a615780806020019051810190613b229190614254565b610a615760405162461bcd60e51b8152600401610445906150bf565b6060611ba7848460008585613b5285613be8565b613b6e5760405162461bcd60e51b815260040161044590614ef6565b60006060866001600160a01b03168587604051613b8b9190614610565b60006040518083038185875af1925050503d8060008114613bc8576040519150601f19603f3d011682016040523d82523d6000602084013e613bcd565b606091505b5091509150613bdd828286613bee565b979650505050505050565b3b151590565b60608315613bfd575081610af9565b825115613c0d5782518084602001fd5b8160405162461bcd60e51b81526004016104459190614812565b604051806101a0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160608152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b50805460008255906000526020600020908101906114419190613e13565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613d1457805160ff1916838001178555613d41565b82800160010185558215613d41579182015b82811115613d41578251825591602001919060010190613d26565b5061234a929150613e13565b828054828255906000526020600020908101928215613da2579160200282015b82811115613da257825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613d6d565b5061234a929150613e2d565b6040518060a0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600060ff168152602001606081525090565b60405180606001604052806000815260200160608152602001606081525090565b61241791905b8082111561234a5760008155600101613e19565b61241791905b8082111561234a5780546001600160a01b0319168155600101613e33565b80516114568161530c565b60008083601f840112613e6d578182fd5b50813567ffffffffffffffff811115613e84578182fd5b60208301915083602080830285010111156125cc57600080fd5b600082601f830112613eae578081fd5b8135613ec1613ebc8261529c565b615275565b818152915060208083019084810181840286018201871015613ee257600080fd5b60005b84811015613f0a578135613ef881615321565b84529282019290820190600101613ee5565b505050505092915050565b600082601f830112613f25578081fd5b8135613f33613ebc8261529c565b818152915060208083019084810160005b84811015613f0a5781358701606080601f19838c03011215613f6557600080fd5b613f6e81615275565b85830135815260408084013567ffffffffffffffff80821115613f9057600080fd5b613f9e8e8a84890101613feb565b8985015284860135915080821115613fb557600080fd5b50613fc48d8983880101613feb565b9183019190915250865250509282019290820190600101613f44565b803561145681615321565b600082601f830112613ffb578081fd5b8135614009613ebc826152bc565b915080825283602082850101111561402057600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112614049578081fd5b8151614057613ebc826152bc565b915080825283602082850101111561406e57600080fd5b610fcd8160208401602086016152e0565b80356114568161530c565b805160ff8116811461145657600080fd5b6000602082840312156140ac578081fd5b8151610af98161530c565b600060208083850312156140c9578182fd5b825167ffffffffffffffff8111156140df578283fd5b80840185601f8201126140f0578384fd5b80519150614100613ebc8361529c565b828152838101908285018585028401860189101561411c578687fd5b8693505b848410156141475780516141338161530c565b835260019390930192918501918501614120565b50979650505050505050565b60006020808385031215614165578182fd5b825167ffffffffffffffff8082111561417c578384fd5b81850186601f82011261418d578485fd5b8051925061419d613ebc8461529c565b83815284810190828601875b86811015614245578151850160a080601f19838f030112156141c9578a8bfd5b6141d281615275565b6141de8e8c8501613e51565b81526141ed8e60408501613e51565b8b820152606083015160408201526142088e6080850161408a565b6060820152818301518981111561421d578c8dfd5b61422b8f8d83870101614039565b6080830152508652505092870192908701906001016141a9565b50909998505050505050505050565b600060208284031215614265578081fd5b8151610af981615321565b600060208284031215614281578081fd5b815167ffffffffffffffff811115614297578182fd5b610fca84828501614039565b6000602082840312156142b4578081fd5b8135610af98161530c565b600080604083850312156142d1578081fd5b82356142dc8161530c565b915060208301356142ec8161530c565b809150509250929050565b60008060006060848603121561430b578081fd5b83356143168161530c565b925060208481013567ffffffffffffffff80821115614333578384fd5b81870188601f820112614344578485fd5b80359250614354613ebc8461529c565b83815284810190828601868602840187018c1015614370578788fd5b8793505b8584101561439b5780356143878161530c565b835260019390930192918601918601614374565b509650505060408701359250808311156143b3578384fd5b50506143c186828701613e9e565b9150509250925092565b600080604083850312156143dd578182fd5b82356143e88161530c565b915060208301356142ec81615321565b600080604083850312156142d1578182fd5b60008060008060008060008060006101008a8c031215614428578687fd5b6144328b8b61407f565b98506144418b60208c0161407f565b975060408a013567ffffffffffffffff8082111561445d578889fd5b6144698d838e01613e5c565b909950975060608c0135915080821115614481578687fd5b61448d8d838e01613f15565b965060808c01359150808211156144a2578586fd5b506144af8c828d01613f15565b9450506144bf8b60a08c01613fe0565b925060c08a0135915060e08a013590509295985092959850929598565b60008060008060008060c087890312156144f4578384fd5b86356144ff8161530c565b9550602087013561450f8161530c565b9450604087013561451f8161530c565b9350606087013592506080870135915060a087013561453d81615321565b809150509295509295509295565b6000806040838503121561455d578182fd5b82356145688161530c565b946020939093013593505050565b600060208284031215614587578081fd5b5051919050565b6001600160a01b03169052565b6000815180845260208085019450808401835b838110156145d35781516001600160a01b0316875295820195908201906001016145ae565b509495945050505050565b15159052565b600081518084526145fc8160208601602086016152e0565b601f01601f19169290920160200192915050565b600082516146228184602087016152e0565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03988916815296909716602087015293151560408601526060850192909252608084015260a083015260c082015260e08101919091526101000190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060018060a01b03808916835280881660208401525085604083015284606083015283608083015260c060a08301526146e560c08301846145e4565b98975050505050505050565b6001600160a01b03929092168252602082015260400190565b600060018060a01b038516825283602083015260606040830152611cc460608301846145e4565b600060208252610af9602083018461459b565b901515815260200190565b9115158252602082015260400190565b600086151582526020868184015260408681850152606060a08186015261478960a086018861459b565b858103608087015286518082528482019085810283018601868a01885b838110156147fe57601f1986840301855281518051845289810151888b8601526147d2898601826145e4565b8a83015191508581038b8701526147e981836145e4565b978c01979550505091890191506001016147a6565b50909e9d5050505050505050505050505050565b600060208252610af960208301846145e4565b6001600160a01b03959095168552602085019390935260408401919091526060830152608082015260a00190565b6020808252818101527f43616e6e6f742068617665206475706c696361746520636f6d706f6e656e7473604082015260600190565b6020808252601c908201527f436f6d706f6e656e7420616d6f756e74206d757374206265203e203000000000604082015260600190565b60208082526050908201527f43616e6e6f7420756e6c6f636b206561726c7920756e6c65737320616c6c207460408201527f61726765747320617265206d657420616e64207261697365546172676574506560608201526f7263656e74616765206973207a65726f60801b608082015260a00190565b60208082526015908201527420b2323932b9b9903737ba1034b71030b93930bc9760591b604082015260600190565b602080825260159082015274115490cc8c081d1c985b9cd9995c8819985a5b1959605a1b604082015260600190565b602080825260159082015274082e4e4c2f240d8cadccee8d040dad2e6dac2e8c6d605b1b604082015260600190565b60208082526028908201527f4d75737420626520612076616c696420616e6420696e697469616c697a65642060408201526729b2ba2a37b5b2b760c11b606082015260800190565b6020808252601490820152730a2eadee8ca40c2e6e6cae840dad2e6dac2e8c6d60631b604082015260600190565b60208082526024908201527f43616e6e6f7420626964206578706c696369746c79206f6e2051756f746520416040820152631cdcd95d60e21b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526021908201527f4269642073697a6520657863656564732061756374696f6e207175616e7469746040820152607960f81b606082015260800190565b6020808252601e908201527f4d7573742062652070656e64696e6720696e697469616c697a6174696f6e0000604082015260600190565b60208082526023908201527f54617267657473206e6f74206d6574206f722071756f7465206173736574203d60408201526207e20360ec1b606082015260800190565b6020808252818101527f51756f7465206173736574207175616e746974792062656c6f77206c696d6974604082015260600190565b60208082526029908201527f4e657720636f6d706f6e656e747320616e6420706172616d73206c656e677468604082015268040dad2e6dac2e8c6d60bb1b606082015260800190565b6020808252601d908201527f526562616c616e6365206d75737420626520696e2070726f6772657373000000604082015260600190565b60208082526022908201527f51756f7465206173736574207175616e746974792065786365656473206c696d6040820152611a5d60f21b606082015260800190565b60208082526015908201527426bab9ba103132903b30b634b21030b230b83a32b960591b604082015260600190565b6020808252601a908201527f41756374696f6e20646972656374696f6e206d69736d61746368000000000000604082015260600190565b6020808252601a908201527f43616e6e6f74206475706c696361746520616464726573736573000000000000604082015260600190565b60208082526021908201527f5072696365206164617074657220636f6e666967206461746120696e76616c696040820152601960fa1b606082015260800190565b6020808252601f908201527f436f6d706f6e656e74206e6f742070617274206f6620726562616c616e636500604082015260600190565b6020808252818101527f53616665436173743a2076616c7565206d75737420626520706f736974697665604082015260600190565b6020808252818101527f496e73756666696369656e742071756f74652061737365742062616c616e6365604082015260600190565b6020808252601c908201527f41646472657373206e6f74207065726d697474656420746f2062696400000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252601e908201527f45787465726e616c20706f736974696f6e73206e6f7420616c6c6f7765640000604082015260600190565b6020808252601d908201527f496e76616c696420706f7374207472616e736665722062616c616e6365000000604082015260600190565b60208082526012908201527115185c99d95d08185b1c9958591e481b595d60721b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b60208082526030908201527f4e657720636f6d706f6e656e742074617267657420756e6974206d757374206260408201526f0652067726561746572207468616e20360841b606082015260800190565b60208082526018908201527f4172726179206c656e677468206d757374206265203e20300000000000000000604082015260600190565b60208082526029908201527f4f6c6420636f6d706f6e656e747320616e6420706172616d73206c656e677468604082015268040dad2e6dac2e8c6d60bb1b606082015260800190565b60208082526028908201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604082015267371034b73a191a9b60c11b606082015260800190565b60208082526023908201527f4d75737420626520636f6e74726f6c6c65722d656e61626c656420536574546f60408201526235b2b760e91b606082015260800190565b6020808252601c908201527f4d7573742062652074686520536574546f6b656e206d616e6167657200000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252600a90820152694120697320656d70747960b01b604082015260600190565b60006020825261517860208301845161458e565b602083015161518a604084018261458e565b50604083015161519d606084018261458e565b5060608301516151b0608084018261458e565b5060808301516101a08060a08501526151cd6101c08501836145e4565b60a086015192506151e160c08601846145de565b60c086015160e0868101919091528601516101008087019190915286015161012080870191909152860151610140808701919091528601516101608087019190915286015161018080870191909152909501519301929092525090919050565b90815260200190565b60008482526060602083015261526360608301856145e4565b82810360408401526135f881856145e4565b60405181810167ffffffffffffffff8111828210171561529457600080fd5b604052919050565b600067ffffffffffffffff8211156152b2578081fd5b5060209081020190565b600067ffffffffffffffff8211156152d2578081fd5b50601f01601f191660200190565b60005b838110156152fb5781810151838201526020016152e3565b838111156128115750506000910152565b6001600160a01b038116811461144157600080fd5b801515811461144157600080fdfea26469706673582212203d1a1aee7ab008878ef36236b470ae0d40662aa4a890c2ac01c8496e2bc7f87064736f6c634300060a0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101585760003560e01c80638d50c6c1116100c3578063d4f005321161007c578063d4f0053214610304578063dc7bc58514610317578063dc8abe2e1461032a578063f47876981461034e578063f77c479114610361578063ff0932a11461037657610158565b80638d50c6c1146102855780638e0f7756146102a5578063b26faa0a146102b8578063c2098812146102cb578063c3824c48146102de578063c4d66de8146102f157610158565b8063421dec4d11610115578063421dec4d1461020257806345e3db3e14610224578063602ab35d146102375780636db4a26214610257578063737531ba1461026a578063847ef08d1461027d57610158565b80630b2c85eb1461015d57806323ab55ec14610187578063270e5590146101a75780632f6c493c146101c757806339a88f80146101dc57806341cefcd1146101ef575b600080fd5b61017061016b3660046143f8565b610389565b60405161017e92919061474f565b60405180910390f35b61019a6101953660046144dc565b6104db565b60405161017e9190615164565b6101ba6101b53660046142a3565b61051b565b60405161017e9190614744565b6101da6101d53660046142a3565b61052e565b005b6101ba6101ea3660046142a3565b610624565b6101ba6101fd3660046142a3565b61062f565b6102156102103660046143f8565b61063a565b60405161017e9392919061524a565b6101ba6102323660046142a3565b610777565b61024a6102453660046142a3565b61078c565b60405161017e9190614731565b6101da6102653660046144dc565b610810565b6101da61027836600461454b565b61091c565b6101da610981565b6102986102933660046142a3565b610a66565b60405161017e9190615241565b6101da6102b336600461440a565b610b00565b6101da6102c63660046142f7565b610e49565b6101ba6102d93660046142a3565b610fa9565b6101ba6102ec3660046142bf565b610fb4565b6101da6102ff3660046142a3565b610fd4565b61024a6103123660046142a3565b6111e1565b6101ba6103253660046142a3565b611263565b61033d6103383660046142a3565b61126e565b60405161017e959493929190614825565b6101da61035c3660046143cb565b6112a8565b610369611306565b60405161017e919061462c565b6101da6103843660046142a3565b611315565b600080836103968161141c565b6104298460046000886001600160a01b03166001600160a01b0316815260200190815260200160002060050180548060200260200160405190810160405280929190818152602001828054801561041657602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116103f8575b505050505061144490919063ffffffff16565b61044e5760405162461bcd60e51b815260040161044590614d43565b60405180910390fd5b6000856001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561048957600080fd5b505afa15801561049d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c19190614576565b90506104ce86868361145c565b9350935050509250929050565b6104e3613c27565b866104ed8161141c565b6104f988888888611583565b610501613c27565b61050e898988888861171b565b9998505050505050505050565b600061052682611b4f565b90505b919050565b600061053982611baf565b9050600061054683611bec565b905081806105515750805b61056d5760405162461bcd60e51b8152600401610445906148bf565b80156105b8576001600160a01b038316600081815260046020526040808220600201829055517f7ebe07e0f6679ed2dd131ed9d9498112c84991ccae90b0568240bf0dbf680d5c9190a25b6001600160a01b03831660008181526004602081905260408083208201839055805163a69df4b560e01b8152905163a69df4b59382840193909282900301818387803b15801561060757600080fd5b505af115801561061b573d6000803e3d6000fd5b50505050505050565b600061052682611bec565b600061052682611c2f565b600260208181526000938452604080852082529284529282902080546001808301805486519281161561010002600019011694909404601f8101879004870282018701909552848152909491939092918301828280156106db5780601f106106b0576101008083540402835291602001916106db565b820191906000526020600020905b8154815290600101906020018083116106be57829003601f168201915b50505060028085018054604080516020601f600019610100600187161502019094169590950492830185900485028101850190915281815295969594509092509083018282801561076d5780601f106107425761010080835404028352916020019161076d565b820191906000526020600020905b81548152906001019060200180831161075057829003601f168201915b5050505050905083565b60036020526000908152604090205460ff1681565b6060816107988161141c565b6001600160a01b0383166000908152600360209081526040918290206001018054835181840281018401909452808452909183018282801561080357602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116107e5575b5050505050915050919050565b600260015414156108335760405162461bcd60e51b815260040161044590615109565b60026001558561084281611ccd565b61084e87878787611583565b610856613c27565b610863888887878761171b565b905061086e81611cf3565b600061087982611d36565b905060008061088784611de9565b9150915083604001516001600160a01b031684602001516001600160a01b031685600001516001600160a01b03167f96310ab47353685e74601a419fddb52db22b6ce0f72cb735c35ff494289dd6423388606001518960a001518a60e0015189898c8e6101800151604051610903989796959493929190614640565b60405180910390a4505060018055505050505050505050565b8161092681611e9e565b6001600160a01b03831660008181526004602081905260409182902001849055517f6a1e9ac0e71aa1dc7854a57bce846b04b1aae20dc994b832098200d9236d1d4a90610974908590615241565b60405180910390a2505050565b336000908152600360205260408120905b60018201548110156109f15760008260020160008460010184815481106109b557fe5b6000918252602080832091909101546001600160a01b031683528201929092526040019020805460ff1916911515919091179055600101610992565b50336000908152600460208190526040822080546001600160a01b031916815560018101839055600281018390556003810183905590810182905590610a3a6005830182613cb5565b5050336000908152600360205260408120805460ff1916815590610a616001830182613cb5565b505050565b6001600160a01b038082166000908152600460208190526040808320805491516370a0823160e01b8152939490939116916370a0823191610aa99187910161462c565b60206040518083038186803b158015610ac157600080fd5b505afa158015610ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af99190614576565b9392505050565b88610b0a81611e9e565b838015610b995750306001600160a01b03168a6001600160a01b031663d7b96d4e6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b5557600080fd5b505afa158015610b69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8d919061409b565b6001600160a01b031614155b15610bf257896001600160a01b031663f83d08ba6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610bd957600080fd5b505af1158015610bed573d6000803e3d6000fd5b505050505b606080610c768c6001600160a01b03166399d50d5d6040518163ffffffff1660e01b815260040160006040518083038186803b158015610c3157600080fd5b505afa158015610c45573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c6d91908101906140b7565b8b8b8b8b611ec4565b909250905060005b8251811015610d8f57610cb6838281518110610c9657fe5b60200260200101518e6001600160a01b0316611f8d90919063ffffffff16565b15610cd35760405162461bcd60e51b815260040161044590614e5c565b818181518110610cdf57fe5b6020026020010151600260008f6001600160a01b03166001600160a01b031681526020019081526020016000206000858481518110610d1a57fe5b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600082015181600001556020820151816001019080519060200190610d68929190613cd3565b5060408201518051610d84916002840191602090910190613cd3565b505050600101610c7e565b506001600160a01b038c8116600090815260046020908152604090912080546001600160a01b031916928e1692909217825542600183015560028201879055600382018690558351610de79260050191850190613d4d565b508a6001600160a01b03168c6001600160a01b03167f2ca831858de887d2ca1c692d1940334f1d3f6c80c9101a306201d66397cf9be68888888787604051610e3395949392919061475f565b60405180910390a3505050505050505050505050565b82610e5381611e9e565b610e63838363ffffffff61201916565b60005b8351811015610fa257610ea085858381518110610e7f57fe5b6020026020010151858481518110610e9357fe5b6020026020010151612047565b828181518110610eac57fe5b602002602001015160036000876001600160a01b03166001600160a01b031681526020019081526020016000206002016000868481518110610eea57fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550838181518110610f3557fe5b60200260200101516001600160a01b0316856001600160a01b03167f4e771e3486d7afcce48115112ca75bc21bc33ac6d6261f7d273b9c5820606717858481518110610f7d57fe5b6020026020010151604051610f929190614744565b60405180910390a3600101610e66565b5050505050565b600061052682611baf565b600082610fc08161141c565b610fca84846121f7565b91505b5092915050565b8033610fe08282612241565b82610fea81612267565b6060846001600160a01b031663802758606040518163ffffffff1660e01b815260040160006040518083038186803b15801561102557600080fd5b505afa158015611039573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526110619190810190614153565b905060005b81518110156110f457611077613dae565b82828151811061108357fe5b60200260200101519050806060015160ff166000146110b45760405162461bcd60e51b815260040161044590614e5c565b6110c18160400151612328565b6001600160a01b038089166000908152600260209081526040808320955190931682529390935290912055600101611066565b5061116e856001600160a01b0316635230c3966040518163ffffffff1660e01b815260040160206040518083038186803b15801561113157600080fd5b505afa158015611145573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111699190614576565b612328565b6001600160a01b03861660008181526004602081905260408083206003019490945583516307ff078f60e11b815293519293630ffe0f1e938183019392909182900301818387803b1580156111c257600080fd5b505af11580156111d6573d6000803e3d6000fd5b505050505050505050565b6060816111ed8161141c565b6001600160a01b03831660009081526004602090815260409182902060050180548351818402810184019094528084529091830182828015610803576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116107e5575050505050915050919050565b60006105268261234e565b6004602081905260009182526040909120805460018201546002830154600384015493909401546001600160a01b03909216939092909185565b816112b281611e9e565b6001600160a01b03831660008181526003602052604090819020805460ff1916851515179055517f1fed19c0eee5ddf8ef482a13e2f0c3ec5c1390b1e39160fe52eabd651ecc7dba90610974908590614744565b6000546001600160a01b031681565b8061131f81611ccd565b61132882611baf565b156113455760405162461bcd60e51b815260040161044590614bec565b61134e82611b4f565b61136a5760405162461bcd60e51b815260040161044590614b2b565b6001600160a01b0382166000908152600460208190526040822001546113ca906113a29061139661240d565b9063ffffffff61241a16565b6001600160a01b0385166000908152600460205260409020600301549063ffffffff61243f16565b6001600160a01b0384166000818152600460205260409081902060030183905551919250907fe4c448aaaad94925b669914540bde1ea0123c0b2320e4cf6ea0ad7a1818a1c9890610974908490615241565b61142581612469565b6114415760405162461bcd60e51b8152600401610445906149c2565b50565b600080611451848461256d565b925050505b92915050565b6000805460405163792aa04f60e01b8152829182916001600160a01b039091169063792aa04f9061149390309085906004016146f1565b60206040518083038186803b1580156114ab57600080fd5b505afa1580156114bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e39190614576565b90506000806000806114f68a8a8a6125d3565b93509350935093508284141561151e5760405162461bcd60e51b815260040161044590614eca565b8181109650866115645761155f6115438661153761240d565b9063ffffffff61262e16565b611553838563ffffffff61262e16565b9063ffffffff61243f16565b611574565b611574828263ffffffff61262e16565b95505050505050935093915050565b6001600160a01b0380851660009081526004602052604090205481169084168114156115c15760405162461bcd60e51b815260040161044590614a38565b806001600160a01b0316836001600160a01b0316146115f25760405162461bcd60e51b815260040161044590614a0a565b6116838460046000886001600160a01b03166001600160a01b03168152602001908152602001600020600501805480602002602001604051908101604052809291908181526020018280548015610416576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116103f857505050505061144490919063ffffffff16565b61169f5760405162461bcd60e51b815260040161044590614d43565b6116b86001600160a01b0386168563ffffffff611f8d16565b156116d55760405162461bcd60e51b815260040161044590614e5c565b6116de85611baf565b156116fb5760405162461bcd60e51b815260040161044590614bec565b60008211610fa25760405162461bcd60e51b815260040161044590614888565b611723613c27565b6001600160a01b038616808252604080516318160ddd60e01b815290516318160ddd91600480820192602092909190829003018186803b15801561176657600080fd5b505afa15801561177a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179e9190614576565b6101808201526117ae8686612670565b6001600160a01b0390811660608301528681166000908152600260208181526040808420948a168452938152918390208101805484516001821615610100026000190190911692909204601f8101849004840283018401909452838252909290918301828280156118605780601f1061183557610100808354040283529160200191611860565b820191906000526020600020905b81548152906001019060200180831161184357829003601f168201915b5050505050816080018190525061187d868683610180015161145c565b60c0830152151560a08201819052821515146118ab5760405162461bcd60e51b815260040161044590614c94565b6000198414156118c1578060c0015193506118e5565b8060c001518411156118e55760405162461bcd60e51b815260040161044590614ab3565b6118f48160a001518787612727565b6001600160a01b039081166040808501919091529181166020808501919091526060840151898316600090815260049092529290206001015491169063104b9b649088908890889061194d90429063ffffffff61262e16565b6001600160a01b038c166000908152600460208190526040918290206002015460808a015192516001600160e01b031960e08a901b16815261199597969594939192016146a8565b60206040518083038186803b1580156119ad57600080fd5b505afa1580156119c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e59190614576565b60e0820181905260a0820151600091611a009190879061277a565b60208301516040516370a0823160e01b81529192506001600160a01b0316906370a0823190611a33908a9060040161462c565b60206040518083038186803b158015611a4b57600080fd5b505afa158015611a5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a839190614576565b61014083015260408083015190516370a0823160e01b81526001600160a01b03909116906370a0823190611abb908a9060040161462c565b60206040518083038186803b158015611ad357600080fd5b505afa158015611ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0b9190614576565b82610160018181525050611b2a8260a0015182868561014001516127a6565b611b398260a001518683612817565b6101208401526101008301525095945050505050565b6001600160a01b0380821660009081526004602052604081208054919290918391611b7c91869116612830565b8254611b929086906001600160a01b03166128cf565b119050611b9e8461234e565b8015611ba75750805b949350505050565b6001600160a01b0381166000908152600460205260408120600281015460018201544291611be3919063ffffffff61241a16565b11159392505050565b6001600160a01b0381166000908152600460205260408120611c0d8361234e565b8015611c1d5750611c1d83611c2f565b8015610af95750600401541592915050565b6001600160a01b0380821660009081526004602052604081208054919290918391611c5c91869116612830565b8254611c729086906001600160a01b03166128cf565b835491109150600090611cb990611c939087906001600160a01b0316612830565b8454600190611cac9089906001600160a01b03166128cf565b919063ffffffff61291816565b90508180611cc45750805b95945050505050565b611cd781336121f7565b6114415760405162461bcd60e51b815260040161044590614de4565b611d0c816040015133836000015184610120015161294f565b60208101516101008201518251611441926001600160a01b0390911691339063ffffffff61295b16565b604080820151825161016084015192516370a0823160e01b81526000938491611dc991906001600160a01b038616906370a0823190611d7990879060040161462c565b60206040518083038186803b158015611d9157600080fd5b505afa158015611da5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115379190614576565b90506000611dd8600083612aa5565b9050611cc483876040015183612b3a565b80516020820151610180830151610140840151600093849390928492611e21926001600160a01b03861692909163ffffffff612be116565b505090506000611e558660400151876101800151886101600151866001600160a01b0316612be1909392919063ffffffff16565b505090506000611e738388610140015161262e90919063ffffffff16565b90506000611e8f8861016001518461262e90919063ffffffff16565b91965090945050505050915091565b611ea88133612cd2565b61141c5760405162461bcd60e51b815260040161044590615088565b815160609081908514611ee95760405162461bcd60e51b815260040161044590614ba3565b8251875114611f0a5760405162461bcd60e51b815260040161044590614fb4565b611f4f8686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b9392505063ffffffff612d60169050565b9150611f5a82612e52565b15611f775760405162461bcd60e51b815260040161044590614853565b611f818385612f01565b90509550959350505050565b600080836001600160a01b031663a7bdad03846040518263ffffffff1660e01b8152600401611fbc919061462c565b60006040518083038186803b158015611fd457600080fd5b505afa158015611fe8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261201091908101906140b7565b51119392505050565b805182511461203a5760405162461bcd60e51b815260040161044590614993565b61204382613049565b5050565b8080156120e257506120e08260036000866001600160a01b03166001600160a01b03168152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610416576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116103f857505050505061144490919063ffffffff16565b155b1561212d576001600160a01b0383811660009081526003602090815260408220600190810180549182018155835291200180546001600160a01b031916918416919091179055610a61565b801580156121c757506121c78260036000866001600160a01b03166001600160a01b03168152602001908152602001600020600101805480602002602001604051908101604052809291908181526020018280548015610416576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116103f857505050505061144490919063ffffffff16565b15610a61576001600160a01b0383166000908152600360205260409020610a61906001018363ffffffff61309016565b6001600160a01b0382166000908152600360205260408120805460ff1680610fca57506001600160a01b038316600090815260028201602052604090205460ff1691505092915050565b61224b8282612cd2565b6120435760405162461bcd60e51b815260040161044590615088565b600054604051631d3af8fb60e21b81526001600160a01b03909116906374ebe3ec9061229790849060040161462c565b60206040518083038186803b1580156122af57600080fd5b505afa1580156122c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e79190614254565b6123035760405162461bcd60e51b815260040161044590615045565b61230c816131bc565b6114415760405162461bcd60e51b815260040161044590614af4565b60008082121561234a5760405162461bcd60e51b815260040161044590614d7a565b5090565b6001600160a01b038116600090815260046020908152604080832060050180548251818502810185019093528083526060938301828280156123b957602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161239b575b50939450600093505050505b8151811015612403576123eb848383815181106123de57fe5b60200260200101516131eb565b156123fb57600092505050610529565b6001016123c5565b5060019392505050565b670de0b6b3a76400005b90565b600082820183811015610af95760405162461bcd60e51b815260040161044590614a7c565b6000610af98261245d85670de0b6b3a764000063ffffffff61326316565b9063ffffffff61329d16565b60008054604051631d3af8fb60e21b81526001600160a01b03909116906374ebe3ec9061249a90859060040161462c565b60206040518083038186803b1580156124b257600080fd5b505afa1580156124c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ea9190614254565b801561052657506040516335fc6c9f60e21b81526001600160a01b0383169063d7f1b27c9061251d90309060040161462c565b60206040518083038186803b15801561253557600080fd5b505afa158015612549573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105269190614254565b81516000908190815b818110156125c057846001600160a01b031686828151811061259457fe5b60200260200101516001600160a01b031614156125b8579250600191506125cc9050565b600101612576565b50600019600092509250505b9250929050565b60008060008060006125e588886128cf565b905060006125f38989612830565b90506000612607888463ffffffff6132df16565b9050600061261b898463ffffffff6132f116565b939b929a50909850919650945050505050565b6000610af983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613330565b6001600160a01b03828116600090815260026020818152604080842094861684529381528383206001908101805486519281161561010002600019011693909304601f81018390048302820183019095528481529293610af993929183018282801561271d5780601f106126f25761010080835404028352916020019161271d565b820191906000526020600020905b81548152906001019060200180831161270057829003601f168201915b505050505061335c565b60008084612750576001600160a01b03808516600090815260046020526040902054168361276e565b6001600160a01b038085166000908152600460205260409020548491165b91509150935093915050565b60008361279657612791838363ffffffff61337316565b611ba7565b611ba7838363ffffffff6132f116565b83156127d157818311156127cc5760405162461bcd60e51b815260040161044590614c23565b612811565b818310156127f15760405162461bcd60e51b815260040161044590614b6e565b808311156128115760405162461bcd60e51b815260040161044590614daf565b50505050565b6000808461282657828461276e565b5091939092509050565b6000610af960046000856001600160a01b03166001600160a01b031681526020019081526020016000206003015461245d61289d866001600160a01b0316635230c3966040518163ffffffff1660e01b815260040160206040518083038186803b15801561113157600080fd5b6001600160a01b038088166000908152600260209081526040808320938a16835292905220549063ffffffff61326316565b6000610af9836001600160a01b03166366cb8d2f846040518263ffffffff1660e01b8152600401612900919061462c565b60206040518083038186803b15801561113157600080fd5b600061292a838363ffffffff61241a16565b8411158015611ba75750612944838363ffffffff61262e16565b909310159392505050565b61281184848484613391565b8015612811576040516370a0823160e01b81526000906001600160a01b038516906370a082319061299090889060040161462c565b60206040518083038186803b1580156129a857600080fd5b505afa1580156129bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e09190614576565b90506129ee858585856134b5565b6040516370a0823160e01b81526000906001600160a01b038616906370a0823190612a1d90899060040161462c565b60206040518083038186803b158015612a3557600080fd5b505afa158015612a49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6d9190614576565b9050612a7f828463ffffffff61262e16565b8114612a9d5760405162461bcd60e51b815260040161044590614e93565b505050505050565b6000805460405163792aa04f60e01b815282916001600160a01b03169063792aa04f90612ad890309088906004016146f1565b60206040518083038186803b158015612af057600080fd5b505afa158015612b04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b289190614576565b9050610fca838263ffffffff61337316565b8015610a6157610a61826000809054906101000a90046001600160a01b03166001600160a01b031663469048406040518163ffffffff1660e01b815260040160206040518083038186803b158015612b9157600080fd5b505afa158015612ba5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc9919061409b565b6001600160a01b03861691908463ffffffff61295b16565b600080600080866001600160a01b03166370a08231896040518263ffffffff1660e01b8152600401612c13919061462c565b60206040518083038186803b158015612c2b57600080fd5b505afa158015612c3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c639190614576565b90506000612c96896001600160a01b03166366cb8d2f8a6040518263ffffffff1660e01b8152600401612900919061462c565b905060008215612cb357612cac888885856135bf565b9050612cb7565b5060005b612cc28a8a83613602565b9199909850909650945050505050565b6000816001600160a01b0316836001600160a01b031663481c6a756040518163ffffffff1660e01b815260040160206040518083038186803b158015612d1757600080fd5b505afa158015612d2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d4f919061409b565b6001600160a01b0316149392505050565b81518151606091908281830167ffffffffffffffff81118015612d8257600080fd5b50604051908082528060200260200182016040528015612dac578160200160208202803683370190505b50905060005b83811015612dfa57868181518110612dc657fe5b6020026020010151828281518110612dda57fe5b6001600160a01b0390921660209283029190910190910152600101612db2565b5060005b82811015612e4857858181518110612e1257fe5b60200260200101518282860181518110612e2857fe5b6001600160a01b0390921660209283029190910190910152600101612dfe565b5095945050505050565b600080825111612e745760405162461bcd60e51b815260040161044590615140565b60005b6001835103811015612ef8576000838281518110612e9157fe5b6020026020010151905060008260010190505b8451811015612eee57848181518110612eb957fe5b60200260200101516001600160a01b0316826001600160a01b03161415612ee65760019350505050610529565b600101612ea4565b5050600101612e77565b50600092915050565b815181516060919080820167ffffffffffffffff81118015612f2257600080fd5b50604051908082528060200260200182016040528015612f5c57816020015b612f49613df2565b815260200190600190039081612f415790505b50925060005b82811015612fb957612f86868281518110612f7957fe5b6020026020010151613780565b858181518110612f9257fe5b6020026020010151848281518110612fa657fe5b6020908102919091010152600101612f62565b5060005b81811015613040576000858281518110612fd357fe5b60200260200101516000015111612ffc5760405162461bcd60e51b815260040161044590614f2d565b61300b858281518110612f7957fe5b84818151811061301757fe5b6020026020010151848285018151811061302d57fe5b6020908102919091010152600101612fbd565b50505092915050565b600081511161306a5760405162461bcd60e51b815260040161044590614f7d565b61307381612e52565b156114415760405162461bcd60e51b815260040161044590614ccb565b6000806130f6848054806020026020016040519081016040528092919081815260200182805480156130eb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116130cd575b50505050508461256d565b91509150806131175760405162461bcd60e51b815260040161044590614935565b8354600019018281146131895784818154811061313057fe5b9060005260206000200160009054906101000a90046001600160a01b031685848154811061315a57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b8480548061319357fe5b600082815260209020810160001990810180546001600160a01b03191690550190555050505050565b6040516353bae5f760e01b81526000906001600160a01b038316906353bae5f79061251d90309060040161462c565b6001600160a01b0380831660009081526004602052604081205490918381169116141561321a57506000611456565b60006132268484612830565b9050600061323485856128cf565b9050600082116132475780821415611451565b6132598282600163ffffffff61291816565b1595945050505050565b60008261327257506000611456565b8282028284828161327f57fe5b0414610af95760405162461bcd60e51b815260040161044590614e1b565b6000610af983836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061382d565b6000610af9838363ffffffff61337316565b60008215806132fe575081155b1561330b57506000611456565b610af96001611396670de0b6b3a764000061245d83611537898963ffffffff61326316565b600081848411156133545760405162461bcd60e51b81526004016104459190614812565b505050900390565b60008061336883613864565b9050610af98161386f565b6000610af9670de0b6b3a764000061245d858563ffffffff61326316565b8015612811576040516370a0823160e01b81526000906001600160a01b038616906370a08231906133c690869060040161462c565b60206040518083038186803b1580156133de57600080fd5b505afa1580156133f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134169190614576565b90506134248585858561392c565b6040516370a0823160e01b81526000906001600160a01b038716906370a082319061345390879060040161462c565b60206040518083038186803b15801561346b57600080fd5b505afa15801561347f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a39190614576565b9050612a7f828463ffffffff61241a16565b801561281157606082826040516024016134d09291906146f1565b60408051601f198184030181529181526020820180516001600160e01b031663a9059cbb60e01b179052516347b7819960e11b81529091506060906001600160a01b03871690638f6f03329061352f908890600090879060040161470a565b600060405180830381600087803b15801561354957600080fd5b505af115801561355d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526135859190810190614270565b805190915015612a9d57808060200190518101906135a39190614254565b612a9d5760405162461bcd60e51b815260040161044590614964565b6000806135e26135d5848863ffffffff61337316565b869063ffffffff61262e16565b90506135f886611553868463ffffffff61262e16565b9695505050505050565b600061360e8484613984565b90508015801561361e5750600082115b156136955761362d8484611f8d565b613690576040516304e3532760e41b81526001600160a01b03851690634e3532709061365d90869060040161462c565b600060405180830381600087803b15801561367757600080fd5b505af115801561368b573d6000803e3d6000fd5b505050505b613712565b8080156136a0575081155b15613712576136af8484611f8d565b61371257604051636f86c89760e01b81526001600160a01b03851690636f86c897906136df90869060040161462c565b600060405180830381600087803b1580156136f957600080fd5b505af115801561370d573d6000803e3d6000fd5b505050505b836001600160a01b0316632ba57d178461372b85613a0b565b6040518363ffffffff1660e01b81526004016137489291906146f1565b600060405180830381600087803b15801561376257600080fd5b505af1158015613776573d6000803e3d6000fd5b5050505050505050565b600061378f826020015161335c565b60408084015190516301e7dafd60e21b81529192506001600160a01b0383169163079f6bf4916137c191600401614812565b60206040518083038186803b1580156137d957600080fd5b505afa1580156137ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138119190614254565b6120435760405162461bcd60e51b815260040161044590614d02565b6000818361384e5760405162461bcd60e51b81526004016104459190614812565b50600083858161385a57fe5b0495945050505050565b805160209091012090565b600080548190613887906001600160a01b0316613a30565b6001600160a01b031663e6d642c530856040518363ffffffff1660e01b81526004016138b49291906146f1565b60206040518083038186803b1580156138cc57600080fd5b505afa1580156138e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613904919061409b565b90506001600160a01b0381166105265760405162461bcd60e51b815260040161044590614c65565b612811846323b872dd60e01b85858560405160240161394d93929190614684565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613aaf565b600080836001600160a01b03166366cb8d2f846040518263ffffffff1660e01b81526004016139b3919061462c565b60206040518083038186803b1580156139cb57600080fd5b505afa1580156139df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a039190614576565b139392505050565b6000600160ff1b821061234a5760405162461bcd60e51b815260040161044590614ffd565b6040516373b2e76b60e11b81526000906001600160a01b0383169063e765ced690613a5f908490600401615241565b60206040518083038186803b158015613a7757600080fd5b505afa158015613a8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610526919061409b565b6060613b04826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613b3e9092919063ffffffff16565b805190915015610a615780806020019051810190613b229190614254565b610a615760405162461bcd60e51b8152600401610445906150bf565b6060611ba7848460008585613b5285613be8565b613b6e5760405162461bcd60e51b815260040161044590614ef6565b60006060866001600160a01b03168587604051613b8b9190614610565b60006040518083038185875af1925050503d8060008114613bc8576040519150601f19603f3d011682016040523d82523d6000602084013e613bcd565b606091505b5091509150613bdd828286613bee565b979650505050505050565b3b151590565b60608315613bfd575081610af9565b825115613c0d5782518084602001fd5b8160405162461bcd60e51b81526004016104459190614812565b604051806101a0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160608152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b50805460008255906000526020600020908101906114419190613e13565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10613d1457805160ff1916838001178555613d41565b82800160010185558215613d41579182015b82811115613d41578251825591602001919060010190613d26565b5061234a929150613e13565b828054828255906000526020600020908101928215613da2579160200282015b82811115613da257825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613d6d565b5061234a929150613e2d565b6040518060a0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600060ff168152602001606081525090565b60405180606001604052806000815260200160608152602001606081525090565b61241791905b8082111561234a5760008155600101613e19565b61241791905b8082111561234a5780546001600160a01b0319168155600101613e33565b80516114568161530c565b60008083601f840112613e6d578182fd5b50813567ffffffffffffffff811115613e84578182fd5b60208301915083602080830285010111156125cc57600080fd5b600082601f830112613eae578081fd5b8135613ec1613ebc8261529c565b615275565b818152915060208083019084810181840286018201871015613ee257600080fd5b60005b84811015613f0a578135613ef881615321565b84529282019290820190600101613ee5565b505050505092915050565b600082601f830112613f25578081fd5b8135613f33613ebc8261529c565b818152915060208083019084810160005b84811015613f0a5781358701606080601f19838c03011215613f6557600080fd5b613f6e81615275565b85830135815260408084013567ffffffffffffffff80821115613f9057600080fd5b613f9e8e8a84890101613feb565b8985015284860135915080821115613fb557600080fd5b50613fc48d8983880101613feb565b9183019190915250865250509282019290820190600101613f44565b803561145681615321565b600082601f830112613ffb578081fd5b8135614009613ebc826152bc565b915080825283602082850101111561402057600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112614049578081fd5b8151614057613ebc826152bc565b915080825283602082850101111561406e57600080fd5b610fcd8160208401602086016152e0565b80356114568161530c565b805160ff8116811461145657600080fd5b6000602082840312156140ac578081fd5b8151610af98161530c565b600060208083850312156140c9578182fd5b825167ffffffffffffffff8111156140df578283fd5b80840185601f8201126140f0578384fd5b80519150614100613ebc8361529c565b828152838101908285018585028401860189101561411c578687fd5b8693505b848410156141475780516141338161530c565b835260019390930192918501918501614120565b50979650505050505050565b60006020808385031215614165578182fd5b825167ffffffffffffffff8082111561417c578384fd5b81850186601f82011261418d578485fd5b8051925061419d613ebc8461529c565b83815284810190828601875b86811015614245578151850160a080601f19838f030112156141c9578a8bfd5b6141d281615275565b6141de8e8c8501613e51565b81526141ed8e60408501613e51565b8b820152606083015160408201526142088e6080850161408a565b6060820152818301518981111561421d578c8dfd5b61422b8f8d83870101614039565b6080830152508652505092870192908701906001016141a9565b50909998505050505050505050565b600060208284031215614265578081fd5b8151610af981615321565b600060208284031215614281578081fd5b815167ffffffffffffffff811115614297578182fd5b610fca84828501614039565b6000602082840312156142b4578081fd5b8135610af98161530c565b600080604083850312156142d1578081fd5b82356142dc8161530c565b915060208301356142ec8161530c565b809150509250929050565b60008060006060848603121561430b578081fd5b83356143168161530c565b925060208481013567ffffffffffffffff80821115614333578384fd5b81870188601f820112614344578485fd5b80359250614354613ebc8461529c565b83815284810190828601868602840187018c1015614370578788fd5b8793505b8584101561439b5780356143878161530c565b835260019390930192918601918601614374565b509650505060408701359250808311156143b3578384fd5b50506143c186828701613e9e565b9150509250925092565b600080604083850312156143dd578182fd5b82356143e88161530c565b915060208301356142ec81615321565b600080604083850312156142d1578182fd5b60008060008060008060008060006101008a8c031215614428578687fd5b6144328b8b61407f565b98506144418b60208c0161407f565b975060408a013567ffffffffffffffff8082111561445d578889fd5b6144698d838e01613e5c565b909950975060608c0135915080821115614481578687fd5b61448d8d838e01613f15565b965060808c01359150808211156144a2578586fd5b506144af8c828d01613f15565b9450506144bf8b60a08c01613fe0565b925060c08a0135915060e08a013590509295985092959850929598565b60008060008060008060c087890312156144f4578384fd5b86356144ff8161530c565b9550602087013561450f8161530c565b9450604087013561451f8161530c565b9350606087013592506080870135915060a087013561453d81615321565b809150509295509295509295565b6000806040838503121561455d578182fd5b82356145688161530c565b946020939093013593505050565b600060208284031215614587578081fd5b5051919050565b6001600160a01b03169052565b6000815180845260208085019450808401835b838110156145d35781516001600160a01b0316875295820195908201906001016145ae565b509495945050505050565b15159052565b600081518084526145fc8160208601602086016152e0565b601f01601f19169290920160200192915050565b600082516146228184602087016152e0565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03988916815296909716602087015293151560408601526060850192909252608084015260a083015260c082015260e08101919091526101000190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060018060a01b03808916835280881660208401525085604083015284606083015283608083015260c060a08301526146e560c08301846145e4565b98975050505050505050565b6001600160a01b03929092168252602082015260400190565b600060018060a01b038516825283602083015260606040830152611cc460608301846145e4565b600060208252610af9602083018461459b565b901515815260200190565b9115158252602082015260400190565b600086151582526020868184015260408681850152606060a08186015261478960a086018861459b565b858103608087015286518082528482019085810283018601868a01885b838110156147fe57601f1986840301855281518051845289810151888b8601526147d2898601826145e4565b8a83015191508581038b8701526147e981836145e4565b978c01979550505091890191506001016147a6565b50909e9d5050505050505050505050505050565b600060208252610af960208301846145e4565b6001600160a01b03959095168552602085019390935260408401919091526060830152608082015260a00190565b6020808252818101527f43616e6e6f742068617665206475706c696361746520636f6d706f6e656e7473604082015260600190565b6020808252601c908201527f436f6d706f6e656e7420616d6f756e74206d757374206265203e203000000000604082015260600190565b60208082526050908201527f43616e6e6f7420756e6c6f636b206561726c7920756e6c65737320616c6c207460408201527f61726765747320617265206d657420616e64207261697365546172676574506560608201526f7263656e74616765206973207a65726f60801b608082015260a00190565b60208082526015908201527420b2323932b9b9903737ba1034b71030b93930bc9760591b604082015260600190565b602080825260159082015274115490cc8c081d1c985b9cd9995c8819985a5b1959605a1b604082015260600190565b602080825260159082015274082e4e4c2f240d8cadccee8d040dad2e6dac2e8c6d605b1b604082015260600190565b60208082526028908201527f4d75737420626520612076616c696420616e6420696e697469616c697a65642060408201526729b2ba2a37b5b2b760c11b606082015260800190565b6020808252601490820152730a2eadee8ca40c2e6e6cae840dad2e6dac2e8c6d60631b604082015260600190565b60208082526024908201527f43616e6e6f7420626964206578706c696369746c79206f6e2051756f746520416040820152631cdcd95d60e21b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526021908201527f4269642073697a6520657863656564732061756374696f6e207175616e7469746040820152607960f81b606082015260800190565b6020808252601e908201527f4d7573742062652070656e64696e6720696e697469616c697a6174696f6e0000604082015260600190565b60208082526023908201527f54617267657473206e6f74206d6574206f722071756f7465206173736574203d60408201526207e20360ec1b606082015260800190565b6020808252818101527f51756f7465206173736574207175616e746974792062656c6f77206c696d6974604082015260600190565b60208082526029908201527f4e657720636f6d706f6e656e747320616e6420706172616d73206c656e677468604082015268040dad2e6dac2e8c6d60bb1b606082015260800190565b6020808252601d908201527f526562616c616e6365206d75737420626520696e2070726f6772657373000000604082015260600190565b60208082526022908201527f51756f7465206173736574207175616e746974792065786365656473206c696d6040820152611a5d60f21b606082015260800190565b60208082526015908201527426bab9ba103132903b30b634b21030b230b83a32b960591b604082015260600190565b6020808252601a908201527f41756374696f6e20646972656374696f6e206d69736d61746368000000000000604082015260600190565b6020808252601a908201527f43616e6e6f74206475706c696361746520616464726573736573000000000000604082015260600190565b60208082526021908201527f5072696365206164617074657220636f6e666967206461746120696e76616c696040820152601960fa1b606082015260800190565b6020808252601f908201527f436f6d706f6e656e74206e6f742070617274206f6620726562616c616e636500604082015260600190565b6020808252818101527f53616665436173743a2076616c7565206d75737420626520706f736974697665604082015260600190565b6020808252818101527f496e73756666696369656e742071756f74652061737365742062616c616e6365604082015260600190565b6020808252601c908201527f41646472657373206e6f74207065726d697474656420746f2062696400000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252601e908201527f45787465726e616c20706f736974696f6e73206e6f7420616c6c6f7765640000604082015260600190565b6020808252601d908201527f496e76616c696420706f7374207472616e736665722062616c616e6365000000604082015260600190565b60208082526012908201527115185c99d95d08185b1c9958591e481b595d60721b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b60208082526030908201527f4e657720636f6d706f6e656e742074617267657420756e6974206d757374206260408201526f0652067726561746572207468616e20360841b606082015260800190565b60208082526018908201527f4172726179206c656e677468206d757374206265203e20300000000000000000604082015260600190565b60208082526029908201527f4f6c6420636f6d706f6e656e747320616e6420706172616d73206c656e677468604082015268040dad2e6dac2e8c6d60bb1b606082015260800190565b60208082526028908201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604082015267371034b73a191a9b60c11b606082015260800190565b60208082526023908201527f4d75737420626520636f6e74726f6c6c65722d656e61626c656420536574546f60408201526235b2b760e91b606082015260800190565b6020808252601c908201527f4d7573742062652074686520536574546f6b656e206d616e6167657200000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252600a90820152694120697320656d70747960b01b604082015260600190565b60006020825261517860208301845161458e565b602083015161518a604084018261458e565b50604083015161519d606084018261458e565b5060608301516151b0608084018261458e565b5060808301516101a08060a08501526151cd6101c08501836145e4565b60a086015192506151e160c08601846145de565b60c086015160e0868101919091528601516101008087019190915286015161012080870191909152860151610140808701919091528601516101608087019190915286015161018080870191909152909501519301929092525090919050565b90815260200190565b60008482526060602083015261526360608301856145e4565b82810360408401526135f881856145e4565b60405181810167ffffffffffffffff8111828210171561529457600080fd5b604052919050565b600067ffffffffffffffff8211156152b2578081fd5b5060209081020190565b600067ffffffffffffffff8211156152d2578081fd5b50601f01601f191660200190565b60005b838110156152fb5781810151838201526020016152e3565b838111156128115750506000910152565b6001600160a01b038116811461144157600080fd5b801515811461144157600080fdfea26469706673582212203d1a1aee7ab008878ef36236b470ae0d40662aa4a890c2ac01c8496e2bc7f87064736f6c634300060a0033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/external/abi/set/ConstantPriceAdapter.json b/external/abi/set/ConstantPriceAdapter.json new file mode 100644 index 00000000..1e5fde3e --- /dev/null +++ b/external/abi/set/ConstantPriceAdapter.json @@ -0,0 +1,116 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ConstantPriceAdapter", + "sourceName": "contracts/protocol/integration/auction-price/ConstantPriceAdapter.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "getDecodedData", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "getEncodedData", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "pure", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_priceAdapterConfigData", + "type": "bytes" + } + ], + "name": "getPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function", + "gas": "0xa7d8c0" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_priceAdapterConfigData", + "type": "bytes" + } + ], + "name": "isPriceAdapterConfigDataValid", + "outputs": [ + { + "internalType": "bool", + "name": "isValid", + "type": "bool" + } + ], + "stateMutability": "pure", + "type": "function", + "gas": "0xa7d8c0" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b506103db806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063079f6bf414610051578063104b9b6414610079578063d3516db61461009a578063fa5ab044146100ad575b600080fd5b61006461005f366004610252565b6100cd565b60405190151581526020015b60405180910390f35b61008c6100873660046102ab565b6100e2565b604051908152602001610070565b61008c6100a8366004610252565b610168565b6100c06100bb366004610325565b610184565b604051610070919061033e565b6000806100d983610168565b15159392505050565b60006100ed82610168565b90506000811161015e5760405162461bcd60e51b815260206004820152603260248201527f436f6e7374616e745072696365416461707465723a205072696365206d75737460448201527102062652067726561746572207468616e20360741b606482015260840160405180910390fd5b9695505050505050565b60008180602001905181019061017e919061038c565b92915050565b60608160405160200161019991815260200190565b6040516020818303038152906040529050919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126101d657600080fd5b813567ffffffffffffffff808211156101f1576101f16101af565b604051601f8301601f19908116603f01168101908282118183101715610219576102196101af565b8160405283815286602085880101111561023257600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006020828403121561026457600080fd5b813567ffffffffffffffff81111561027b57600080fd5b610287848285016101c5565b949350505050565b80356001600160a01b03811681146102a657600080fd5b919050565b60008060008060008060c087890312156102c457600080fd5b6102cd8761028f565b95506102db6020880161028f565b945060408701359350606087013592506080870135915060a087013567ffffffffffffffff81111561030c57600080fd5b61031889828a016101c5565b9150509295509295509295565b60006020828403121561033757600080fd5b5035919050565b600060208083528351808285015260005b8181101561036b5785810183015185820160400152820161034f565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561039e57600080fd5b505191905056fea2646970667358221220a8ec33f8607b508221083122084f69a19ce574994389406865764509edb6536764736f6c63430008110033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c8063079f6bf414610051578063104b9b6414610079578063d3516db61461009a578063fa5ab044146100ad575b600080fd5b61006461005f366004610252565b6100cd565b60405190151581526020015b60405180910390f35b61008c6100873660046102ab565b6100e2565b604051908152602001610070565b61008c6100a8366004610252565b610168565b6100c06100bb366004610325565b610184565b604051610070919061033e565b6000806100d983610168565b15159392505050565b60006100ed82610168565b90506000811161015e5760405162461bcd60e51b815260206004820152603260248201527f436f6e7374616e745072696365416461707465723a205072696365206d75737460448201527102062652067726561746572207468616e20360741b606482015260840160405180910390fd5b9695505050505050565b60008180602001905181019061017e919061038c565b92915050565b60608160405160200161019991815260200190565b6040516020818303038152906040529050919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126101d657600080fd5b813567ffffffffffffffff808211156101f1576101f16101af565b604051601f8301601f19908116603f01168101908282118183101715610219576102196101af565b8160405283815286602085880101111561023257600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006020828403121561026457600080fd5b813567ffffffffffffffff81111561027b57600080fd5b610287848285016101c5565b949350505050565b80356001600160a01b03811681146102a657600080fd5b919050565b60008060008060008060c087890312156102c457600080fd5b6102cd8761028f565b95506102db6020880161028f565b945060408701359350606087013592506080870135915060a087013567ffffffffffffffff81111561030c57600080fd5b61031889828a016101c5565b9150509295509295509295565b60006020828403121561033757600080fd5b5035919050565b600060208083528351808285015260005b8181101561036b5785810183015185820160400152820161034f565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561039e57600080fd5b505191905056fea2646970667358221220a8ec33f8607b508221083122084f69a19ce574994389406865764509edb6536764736f6c63430008110033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/external/contracts/set/AuctionRebalanceModuleV1.sol b/external/contracts/set/AuctionRebalanceModuleV1.sol new file mode 100644 index 00000000..cddc5e8b --- /dev/null +++ b/external/contracts/set/AuctionRebalanceModuleV1.sol @@ -0,0 +1,1346 @@ +/* + Copyright 2023 Index Coop + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache License, Version 2.0 +*/ + +pragma solidity 0.6.10; +pragma experimental "ABIEncoderV2"; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { Math } from "@openzeppelin/contracts/math/Math.sol"; +import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import { SafeCast } from "@openzeppelin/contracts/utils/SafeCast.sol"; +import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; + +import { AddressArrayUtils } from "../../../lib/AddressArrayUtils.sol"; +import { IAuctionPriceAdapterV1 } from "../../../interfaces/IAuctionPriceAdapterV1.sol"; +import { IController } from "../../../interfaces/IController.sol"; +import { Invoke } from "../../lib/Invoke.sol"; +import { ISetToken } from "../../../interfaces/ISetToken.sol"; +import { ModuleBase } from "../../lib/ModuleBase.sol"; +import { Position } from "../../lib/Position.sol"; +import { PreciseUnitMath } from "../../../lib/PreciseUnitMath.sol"; + +/** + * @title AuctionRebalanceModuleV1 + * @author Index Coop + * @notice Facilitates rebalances for index sets via single-asset auctions. Managers initiate + * rebalances specifying target allocations in precise units (scaled by 10^18), quote asset + * (e.g., WETH, USDC), auction parameters per component, and rebalance duration through + * startRebalance(). Bidders can participate via bid() for individual components. Excess + * quote asset can be managed by proportionally increasing the targets using raiseAssetTargets(). + * + * @dev Compatible with StreamingFeeModule and BasicIssuanceModule. Review compatibility if used + * with additional modules. + * @dev WARNING: If rebalances don't lock the SetToken, there's potential for bids to be front-run + * by sizable issuance/redemption. This could lead to the SetToken not approaching its target allocation + * proportionately to the bid size. To counteract this risk, a supply cap can be applied to the SetToken, + * allowing regular issuance/redemption while preventing front-running with large issuance/redemption. + * @dev WARNING: This contract does NOT support ERC-777 component tokens or quote assets. + * @dev WARNING: Please note that the behavior of block.timestamp varies across different EVM chains. + * This contract does not incorporate additional checks for unique behavior or for elements like sequencer uptime. + * Ensure you understand these characteristics when interacting with the contract on different EVM chains. + */ +contract AuctionRebalanceModuleV1 is ModuleBase, ReentrancyGuard { + using SafeCast for int256; + using SafeCast for uint256; + using SafeMath for uint256; + using Position for uint256; + using Math for uint256; + using Position for ISetToken; + using Invoke for ISetToken; + using AddressArrayUtils for address[]; + using AddressArrayUtils for IERC20[]; + + /* ============ Structs ============ */ + + struct AuctionExecutionParams { + uint256 targetUnit; // Target quantity of the component in Set, in precise units (10 ** 18). + string priceAdapterName; // Identifier for the price adapter to be used. + bytes priceAdapterConfigData; // Encoded data for configuring the chosen price adapter. + } + + struct BidPermissionInfo { + bool isAnyoneAllowedToBid; // Flag indicating if bids are open to anyone (true) or restricted (false). + address[] biddersHistory; // List of addresses that have been permissioned to bid. + mapping(address => bool) bidAllowList; // Mapping of addresses to a boolean indicating if they are allowed to bid. + } + + struct RebalanceInfo { + IERC20 quoteAsset; // Reference to the ERC20 token used to quote auctions. + uint256 rebalanceStartTime; // Unix timestamp marking the start of the rebalance. + uint256 rebalanceDuration; // Duration of the rebalance in seconds. + uint256 positionMultiplier; // Position multiplier when target units were calculated. + uint256 raiseTargetPercentage; // Optional percentage to increase all target units if allowed, in precise units. + address[] rebalanceComponents; // List of component tokens involved in the rebalance. + } + + struct BidInfo { + ISetToken setToken; // Instance of the SetToken contract that is being rebalanced. + IERC20 sendToken; // The ERC20 token being sent in this bid. + IERC20 receiveToken; // The ERC20 token being received in this bid. + IAuctionPriceAdapterV1 priceAdapter; // Instance of the price adapter contract used for this bid. + bytes priceAdapterConfigData; // Data for configuring the price adapter. + bool isSellAuction; // Indicates if this is a sell auction (true) or a buy auction (false). + uint256 auctionQuantity; // The quantity of the component being auctioned. + uint256 componentPrice; // The price of the component as quoted by the price adapter. + uint256 quantitySentBySet; // Quantity of tokens sent by SetToken in this bid. + uint256 quantityReceivedBySet; // Quantity of tokens received by SetToken in this bid. + uint256 preBidTokenSentBalance; // Balance of tokens being sent by SetToken before the bid. + uint256 preBidTokenReceivedBalance; // Balance of tokens being received by SetToken before the bid. + uint256 setTotalSupply; // Total supply of the SetToken at the time of the bid. + } + + /* ============ Events ============ */ + + /** + * @dev Emitted when the target percentage increase is modified via setRaiseTargetPercentage() + * @param setToken Reference to the SetToken undergoing rebalancing + * @param newRaiseTargetPercentage Updated percentage for potential target unit increases, in precise units (10 ** 18) + */ + event RaiseTargetPercentageUpdated( + ISetToken indexed setToken, + uint256 newRaiseTargetPercentage + ); + + /** + * @dev Emitted upon calling raiseAssetTargets() + * @param setToken Reference to the SetToken undergoing rebalancing + * @param newPositionMultiplier Updated position multiplier for the SetToken rebalance + */ + event AssetTargetsRaised( + ISetToken indexed setToken, + uint256 newPositionMultiplier + ); + + /** + * @dev Emitted upon toggling the bid permission setting via setAnyoneBid() + * @param setToken Reference to the SetToken undergoing rebalancing + * @param isAnyoneAllowedToBid Flag indicating if bids are open to all (true) or restricted (false) + */ + event AnyoneBidUpdated( + ISetToken indexed setToken, + bool isAnyoneAllowedToBid + ); + + /** + * @dev Emitted when the bidding status of an address is changed via setBidderStatus() + * @param setToken Reference to the SetToken undergoing rebalancing + * @param bidder Address whose bidding permission status is toggled + * @param isBidderAllowed Flag indicating if the address is allowed (true) or not allowed (false) to bid + */ + event BidderStatusUpdated( + ISetToken indexed setToken, + address indexed bidder, + bool isBidderAllowed + ); + + /** + * @dev Emitted when a rebalance is initiated using the startRebalance() function. + * @param setToken Instance of the SetToken contract that is undergoing rebalancing. + * @param quoteAsset The ERC20 token that is used as a quote currency for the auctions. + * @param isSetTokenLocked Indicates if the rebalance process locks the SetToken (true) or not (false). + * @param rebalanceDuration Duration of the rebalance process in seconds. + * @param initialPositionMultiplier Position multiplier when target units were calculated. + * @param componentsInvolved Array of addresses of the component tokens involved in the rebalance. + * @param auctionParameters Array of AuctionExecutionParams structs, containing auction parameters for each component token. + */ + event RebalanceStarted( + ISetToken indexed setToken, + IERC20 indexed quoteAsset, + bool isSetTokenLocked, + uint256 rebalanceDuration, + uint256 initialPositionMultiplier, + address[] componentsInvolved, + AuctionExecutionParams[] auctionParameters + ); + + /** + * @dev Emitted upon execution of a bid via the bid() function. + * @param setToken Instance of the SetToken contract that is being rebalanced. + * @param sendToken The ERC20 token that is being sent by the bidder. + * @param receiveToken The ERC20 token that is being received by the bidder. + * @param bidder The address of the bidder. + * @param priceAdapter Instance of the price adapter contract used for this bid. + * @param isSellAuction Indicates if this is a sell auction (true) or a buy auction (false). + * @param price The price of the component in precise units (10 ** 18). + * @param netQuantitySentBySet The net amount of tokens sent by the SetToken in the bid. + * @param netQuantityReceivedBySet The net amount of tokens received by the SetToken in the bid. + * @param protocolFee The amount of the received token allocated as a protocol fee. + * @param setTotalSupply The total supply of the SetToken at the time of the bid. + */ + event BidExecuted( + ISetToken indexed setToken, + address indexed sendToken, + address indexed receiveToken, + address bidder, + IAuctionPriceAdapterV1 priceAdapter, + bool isSellAuction, + uint256 price, + uint256 netQuantitySentBySet, + uint256 netQuantityReceivedBySet, + uint256 protocolFee, + uint256 setTotalSupply + ); + + /** + * @dev Emitted when a locked rebalance is concluded early via the unlock() function. + * @param setToken Instance of the SetToken contract that is being rebalanced. + */ + event LockedRebalanceEndedEarly( + ISetToken indexed setToken + ); + + + /* ============ Constants ============ */ + + uint256 private constant AUCTION_MODULE_V1_PROTOCOL_FEE_INDEX = 0; // Index of the protocol fee percentage assigned to this module in the Controller. + + /* ============ State Variables ============ */ + + mapping(ISetToken => mapping(IERC20 => AuctionExecutionParams)) public executionInfo; // Maps SetToken to component tokens and their respective auction execution parameters. + mapping(ISetToken => BidPermissionInfo) public permissionInfo; // Maps SetToken to information regarding bid permissions during a rebalance. + mapping(ISetToken => RebalanceInfo) public rebalanceInfo; // Maps SetToken to data relevant to the most recent rebalance. + + /* ============ Modifiers ============ */ + + modifier onlyAllowedBidder(ISetToken _setToken) { + _validateOnlyAllowedBidder(_setToken); + _; + } + + /* ============ Constructor ============ */ + + constructor(IController _controller) public ModuleBase(_controller) {} + + /* ============ External Functions ============ */ + + /** + * @dev MANAGER ONLY: Initiates the rebalance process by setting target allocations for the SetToken. Opens auctions + * for filling by the Set's designated bidders. The function takes in new components to be added with their target units + * and existing components with updated target units (set to 0 if removing). A positionMultiplier is supplied to adjust + * target units, e.g., in cases where fee accrual affects the positionMultiplier of the SetToken, ensuring proportional + * allocation among components. If target allocations are not met within the specified duration, the rebalance concludes + * with the allocations achieved. + * + * @dev WARNING: If rebalances don't lock the SetToken, enforce a supply cap on the SetToken to prevent front-running. + * + * @param _setToken The SetToken to be rebalanced. + * @param _quoteAsset ERC20 token used as the quote asset in auctions. + * @param _newComponents Addresses of new components to be added. + * @param _newComponentsAuctionParams AuctionExecutionParams for new components, indexed corresponding to _newComponents. + * @param _oldComponentsAuctionParams AuctionExecutionParams for existing components, indexed corresponding to + * the current component positions. Set to 0 for components being removed. + * @param _shouldLockSetToken Indicates if the rebalance should lock the SetToken. + * @param _rebalanceDuration Duration of the rebalance in seconds. + * @param _initialPositionMultiplier Position multiplier at the start of the rebalance. + */ + function startRebalance( + ISetToken _setToken, + IERC20 _quoteAsset, + address[] calldata _newComponents, + AuctionExecutionParams[] memory _newComponentsAuctionParams, + AuctionExecutionParams[] memory _oldComponentsAuctionParams, + bool _shouldLockSetToken, + uint256 _rebalanceDuration, + uint256 _initialPositionMultiplier + ) + external + onlyManagerAndValidSet(_setToken) + { + // Lock the SetToken if the _shouldLockSetToken flag is true and the SetToken is not already locked by this module + if (_shouldLockSetToken && _setToken.locker() != address(this)) { + _setToken.lock(); + } + + // Aggregate components and auction parameters + (address[] memory allComponents, AuctionExecutionParams[] memory allAuctionParams) = _aggregateComponentsAndAuctionParams( + _setToken.getComponents(), + _newComponents, + _newComponentsAuctionParams, + _oldComponentsAuctionParams + ); + + // Set the execution information + for (uint256 i = 0; i < allComponents.length; i++) { + require(!_setToken.hasExternalPosition(allComponents[i]), "External positions not allowed"); + executionInfo[_setToken][IERC20(allComponents[i])] = allAuctionParams[i]; + } + + // Set the rebalance information + rebalanceInfo[_setToken].quoteAsset = _quoteAsset; + rebalanceInfo[_setToken].rebalanceStartTime = block.timestamp; + rebalanceInfo[_setToken].rebalanceDuration = _rebalanceDuration; + rebalanceInfo[_setToken].positionMultiplier = _initialPositionMultiplier; + rebalanceInfo[_setToken].rebalanceComponents = allComponents; + + // Emit the RebalanceStarted event + emit RebalanceStarted(_setToken, _quoteAsset, _shouldLockSetToken, _rebalanceDuration, _initialPositionMultiplier, allComponents, allAuctionParams); + } + + /** + * @dev ACCESS LIMITED: Only approved addresses can call this function unless isAnyoneAllowedToBid is enabled. This function + * is used to push the current component units closer to the target units defined in startRebalance(). + * + * Bidders specify the amount of the component they intend to buy or sell, and also specify the maximum/minimum amount + * of the quote asset they are willing to spend/receive. If the component amount is max uint256, the bid will fill + * the remaining amount to reach the target. + * + * The auction parameters, which are set by the manager, are used to determine the price of the component. Any bids that + * either don't move the component units towards the target, or overshoot the target, will be reverted. + * + * If protocol fees are enabled, they are collected in the token received in a bid. + * + * SELL AUCTIONS: + * At the start of the rebalance, sell auctions are available to be filled in their full size. + * + * BUY AUCTIONS: + * Buy auctions can be filled up to the amount of quote asset available in the SetToken. This means that if the SetToken + * does not contain the quote asset as a component, buy auctions cannot be bid on until sell auctions have been executed + * and there is quote asset available in the SetToken. + * + * @param _setToken The SetToken to be rebalanced. + * @param _component The component for which the auction is to be bid on. + * @param _quoteAsset The ERC20 token expected to be used as the quote asset by the bidder + * @param _componentAmount The amount of component in the bid. + * @param _quoteAssetLimit The maximum or minimum amount of quote asset that can be spent or received during the bid. + * @param _isSellAuction The direction of the auction expected by the bidder + */ + function bid( + ISetToken _setToken, + IERC20 _component, + IERC20 _quoteAsset, + uint256 _componentAmount, + uint256 _quoteAssetLimit, + bool _isSellAuction + ) + external + nonReentrant + onlyAllowedBidder(_setToken) + { + // Validate whether the bid targets are legitimate + _validateBidTargets(_setToken, _component, _quoteAsset, _componentAmount); + + // Create the bid information structure + BidInfo memory bidInfo = _createBidInfo(_setToken, _component, _componentAmount, _quoteAssetLimit, _isSellAuction); + + // Execute the token transfer specified in the bid information + _executeBid(bidInfo); + + // Accrue protocol fee and store the amount + uint256 protocolFeeAmount = _accrueProtocolFee(bidInfo); + + // Update the position state and store the net amounts + (uint256 netAmountSent, uint256 netAmountReceived) = _updatePositionState(bidInfo); + + // Emit the BidExecuted event + emit BidExecuted( + bidInfo.setToken, + address(bidInfo.sendToken), + address(bidInfo.receiveToken), + msg.sender, + bidInfo.priceAdapter, + bidInfo.isSellAuction, + bidInfo.componentPrice, + netAmountSent, + netAmountReceived, + protocolFeeAmount, + bidInfo.setTotalSupply + ); + } + + /** + * @dev ACCESS LIMITED: Increases asset targets uniformly when all target units have been met but there is remaining quote asset. + * Can be called multiple times if necessary. Targets are increased by the percentage specified by raiseAssetTargetsPercentage set by the manager. + * This helps in reducing tracking error and providing greater granularity in reaching an equilibrium between the excess quote asset + * and the components to be purchased. However, excessively raising targets may result in under-allocating to the quote asset as more of + * it is spent buying components to meet the new targets. + * + * @param _setToken The SetToken to be rebalanced. + */ + function raiseAssetTargets(ISetToken _setToken) + external + onlyAllowedBidder(_setToken) + virtual + { + // Ensure the rebalance is in progress + require(!_isRebalanceDurationElapsed(_setToken), "Rebalance must be in progress"); + + // Ensure that all targets are met and there is excess quote asset + require(_canRaiseAssetTargets(_setToken), "Targets not met or quote asset =~ 0"); + + // Calculate the new positionMultiplier + uint256 newPositionMultiplier = rebalanceInfo[_setToken].positionMultiplier.preciseDiv( + PreciseUnitMath.preciseUnit().add(rebalanceInfo[_setToken].raiseTargetPercentage) + ); + + // Update the positionMultiplier in the RebalanceInfo struct + rebalanceInfo[_setToken].positionMultiplier = newPositionMultiplier; + + // Emit the AssetTargetsRaised event + emit AssetTargetsRaised(_setToken, newPositionMultiplier); + } + + /** + * @dev Unlocks the SetToken after rebalancing. Can be called once the rebalance duration has elapsed. + * Can only be called before the rebalance duration has elapsed if all targets are met, there is excess + * or at-target quote asset, and raiseTargetPercentage is zero. Resets the raiseTargetPercentage to zero. + * + * @param _setToken The SetToken to be unlocked. + */ + function unlock(ISetToken _setToken) external { + bool isRebalanceDurationElapsed = _isRebalanceDurationElapsed(_setToken); + bool canUnlockEarly = _canUnlockEarly(_setToken); + + // Ensure that either the rebalance duration has elapsed or the conditions for early unlock are met + require(isRebalanceDurationElapsed || canUnlockEarly, "Cannot unlock early unless all targets are met and raiseTargetPercentage is zero"); + + // If unlocking early, update the state + if (canUnlockEarly) { + delete rebalanceInfo[_setToken].rebalanceDuration; + emit LockedRebalanceEndedEarly(_setToken); + } + + // Reset the raiseTargetPercentage to zero + rebalanceInfo[_setToken].raiseTargetPercentage = 0; + + // Unlock the SetToken + _setToken.unlock(); + } + + /** + * @dev MANAGER ONLY: Sets the percentage by which the target units for all components can be increased. + * Can be called at any time by the manager. + * + * @param _setToken The SetToken to be rebalanced. + * @param _raiseTargetPercentage The percentage (in precise units) by which the target units can be increased. + */ + function setRaiseTargetPercentage( + ISetToken _setToken, + uint256 _raiseTargetPercentage + ) + external + onlyManagerAndValidSet(_setToken) + { + // Update the raise target percentage in the RebalanceInfo struct + rebalanceInfo[_setToken].raiseTargetPercentage = _raiseTargetPercentage; + + // Emit an event to log the updated raise target percentage + emit RaiseTargetPercentageUpdated(_setToken, _raiseTargetPercentage); + } + + /** + * @dev MANAGER ONLY: Toggles the permission status of specified addresses to call the `bid()` function. + * The manager can call this function at any time. + * + * @param _setToken The SetToken being rebalanced. + * @param _bidders An array of addresses whose bidding permission status is to be toggled. + * @param _statuses An array of booleans indicating the new bidding permission status for each corresponding address in `_bidders`. + */ + function setBidderStatus( + ISetToken _setToken, + address[] memory _bidders, + bool[] memory _statuses + ) + external + onlyManagerAndValidSet(_setToken) + { + // Validate that the input arrays have the same length + _bidders.validatePairsWithArray(_statuses); + + // Iterate through the input arrays and update the permission status for each bidder + for (uint256 i = 0; i < _bidders.length; i++) { + _updateBiddersHistory(_setToken, _bidders[i], _statuses[i]); + permissionInfo[_setToken].bidAllowList[_bidders[i]] = _statuses[i]; + + // Emit an event to log the updated permission status + emit BidderStatusUpdated(_setToken, _bidders[i], _statuses[i]); + } + } + + /** + * @dev MANAGER ONLY: Toggles whether or not anyone is allowed to call the `bid()` function. + * If set to true, it bypasses the bidAllowList, allowing any address to call the `bid()` function. + * The manager can call this function at any time. + * + * @param _setToken The SetToken instance. + * @param _status A boolean indicating if anyone can bid. + */ + function setAnyoneBid( + ISetToken _setToken, + bool _status + ) + external + onlyManagerAndValidSet(_setToken) + { + // Update the anyoneBid status in the PermissionInfo struct + permissionInfo[_setToken].isAnyoneAllowedToBid = _status; + + // Emit an event to log the updated anyoneBid status + emit AnyoneBidUpdated(_setToken, _status); + } + + + /** + * @dev MANAGER ONLY: Initializes the module for a SetToken, enabling access to AuctionModuleV1 for rebalances. + * Retrieves the current units for each asset in the Set and sets the targetUnit to match the current unit, effectively + * preventing any bidding until `startRebalance()` is explicitly called. The position multiplier is also logged to ensure that + * any changes to the position multiplier do not unintentionally open the Set for rebalancing. + * + * @param _setToken Address of the Set Token + */ + function initialize(ISetToken _setToken) + external + onlySetManager(_setToken, msg.sender) + onlyValidAndPendingSet(_setToken) + { + ISetToken.Position[] memory positions = _setToken.getPositions(); + + for (uint256 i = 0; i < positions.length; i++) { + ISetToken.Position memory position = positions[i]; + require(position.positionState == 0, "External positions not allowed"); + executionInfo[_setToken][IERC20(position.component)].targetUnit = position.unit.toUint256(); + } + + rebalanceInfo[_setToken].positionMultiplier = _setToken.positionMultiplier().toUint256(); + _setToken.initializeModule(); + } + + + /** + * @dev Called by a SetToken to notify that this module was removed from the SetToken. + * Clears the `rebalanceInfo` and `permissionsInfo` of the calling SetToken. + * IMPORTANT: The auction execution settings of the SetToken, including auction parameters, + * are NOT DELETED. Restoring a previously removed module requires careful initialization of + * the execution settings. + */ + function removeModule() external override { + BidPermissionInfo storage tokenPermissionInfo = permissionInfo[ISetToken(msg.sender)]; + + for (uint256 i = 0; i < tokenPermissionInfo.biddersHistory.length; i++) { + tokenPermissionInfo.bidAllowList[tokenPermissionInfo.biddersHistory[i]] = false; + } + + delete rebalanceInfo[ISetToken(msg.sender)]; + delete permissionInfo[ISetToken(msg.sender)]; + } + + + /* ============ External View Functions ============ */ + + /** + * @dev Checks externally if the rebalance duration has elapsed for the given SetToken. + * + * @param _setToken The SetToken whose rebalance duration is being checked. + * @return bool True if the rebalance duration has elapsed; false otherwise. + */ + function isRebalanceDurationElapsed(ISetToken _setToken) external view returns (bool) { + return _isRebalanceDurationElapsed(_setToken); + } + + /** + * @dev Retrieves the array of components that are involved in the rebalancing of the given SetToken. + * + * @param _setToken Instance of the SetToken. + * + * @return address[] Array of component addresses involved in the rebalance. + */ + function getRebalanceComponents(ISetToken _setToken) + external + view + onlyValidAndInitializedSet(_setToken) + returns (address[] memory) + { + return rebalanceInfo[_setToken].rebalanceComponents; + } + + /** + * @dev Calculates the quantity of a component involved in the rebalancing of the given SetToken, + * and determines if the component is being bought or sold. + * + * @param _setToken Instance of the SetToken being rebalanced. + * @param _component Instance of the IERC20 component to bid on. + * + * @return isSellAuction Indicates if this is a sell auction (true) or a buy auction (false). + * @return componentQuantity Quantity of the component involved in the bid. + */ + function getAuctionSizeAndDirection( + ISetToken _setToken, + IERC20 _component + ) + external + view + onlyValidAndInitializedSet(_setToken) + returns (bool isSellAuction, uint256 componentQuantity) + { + require( + rebalanceInfo[_setToken].rebalanceComponents.contains(address(_component)), + "Component not part of rebalance" + ); + + uint256 totalSupply = _setToken.totalSupply(); + return _calculateAuctionSizeAndDirection(_setToken, _component, totalSupply); + } + + /** + * @dev Retrieves the balance of the quote asset for a given SetToken. + * + * @param _setToken The SetToken whose quote asset balance is being retrieved. + * @return uint256 The balance of the quote asset. + */ + function getQuoteAssetBalance(ISetToken _setToken) external view returns (uint256) { + RebalanceInfo storage rebalance = rebalanceInfo[_setToken]; + return IERC20(rebalance.quoteAsset).balanceOf(address(_setToken)); + } + + /** + * @dev Generates a preview of the bid for a given component in the rebalancing of the SetToken. + * It calculates the quantity of the component that will be exchanged and the direction of exchange. + * + * @param _setToken Instance of the SetToken being rebalanced. + * @param _component Instance of the component auction to bid on. + * @param _quoteAsset The ERC20 token expected to be used as the quote asset by the bidder + * @param _componentQuantity Quantity of the component involved in the bid. + * @param _quoteQuantityLimit Maximum or minimum amount of quote asset spent or received during the bid. + * @param _isSellAuction The direction of the auction expected by the bidder + * + * @return BidInfo Struct containing data for the bid. + */ + function getBidPreview( + ISetToken _setToken, + IERC20 _component, + IERC20 _quoteAsset, + uint256 _componentQuantity, + uint256 _quoteQuantityLimit, + bool _isSellAuction + ) + external + view + onlyValidAndInitializedSet(_setToken) + returns (BidInfo memory) + { + _validateBidTargets(_setToken, _component, _quoteAsset, _componentQuantity); + BidInfo memory bidInfo = _createBidInfo(_setToken, _component, _componentQuantity, _quoteQuantityLimit, _isSellAuction); + + return bidInfo; + } + + /** + * @dev Checks externally if the conditions for early unlock are met. + * + * @param _setToken The SetToken being checked. + * @return bool True if early unlock conditions are met; false otherwise. + */ + function canUnlockEarly(ISetToken _setToken) external view returns (bool) { + return _canUnlockEarly(_setToken); + } + + /** + * @dev Checks externally if the conditions to raise asset targets are met. + * + * @param _setToken The SetToken being checked. + * @return bool True if conditions to raise asset targets are met; false otherwise. + */ + function canRaiseAssetTargets(ISetToken _setToken) external view returns (bool) { + return _canRaiseAssetTargets(_setToken); + } + + /** + * @dev Checks externally if all target units for components have been met. + * + * @param _setToken Instance of the SetToken to be rebalanced. + * @return bool True if all component's target units have been met; false otherwise. + */ + function allTargetsMet(ISetToken _setToken) external view returns (bool) { + return _allTargetsMet(_setToken); + } + + /** + * @dev Checks externally if the quote asset is in excess or at target. + * + * @param _setToken The SetToken being checked. + * @return bool True if the quote asset is in excess or at target; false otherwise. + */ + function isQuoteAssetExcessOrAtTarget(ISetToken _setToken) external view returns (bool) { + return _isQuoteAssetExcessOrAtTarget(_setToken); + } + + /** + * @dev Determines whether the given bidder address is allowed to participate in the auction. + * + * @param _setToken Instance of the SetToken for which the bid is being placed. + * @param _bidder Address of the bidder. + * + * @return bool True if the given `_bidder` is permitted to bid, false otherwise. + */ + function isAllowedBidder(ISetToken _setToken, address _bidder) + external + view + onlyValidAndInitializedSet(_setToken) + returns (bool) + { + return _isAllowedBidder(_setToken, _bidder); + } + + /** + * @dev Retrieves the list of addresses that are permitted to participate in the auction by calling `bid()`. + * + * @param _setToken Instance of the SetToken for which to retrieve the list of allowed bidders. + * + * @return address[] Array of addresses representing the allowed bidders. + */ + function getAllowedBidders(ISetToken _setToken) + external + view + onlyValidAndInitializedSet(_setToken) + returns (address[] memory) + { + return permissionInfo[_setToken].biddersHistory; + } + + /* ============ Internal Functions ============ */ + + /** + * @dev Aggregates the current SetToken components with the new components and validates their auction parameters. + * Ensures that the sizes of the new components and new auction parameters arrays are the same, and that the number of current component auction parameters + * matches the number of current components. Additionally, it validates that the price adapter exists, the price adapter configuration data is valid for the adapter, + * and the target unit is greater than zero for new components. The function reverts if there is a duplicate component or if the array lengths are mismatched. + * + * @param _currentComponents The current set of SetToken components. + * @param _newComponents The new components to add to the allocation. + * @param _newComponentsAuctionParams The auction params for the new components, corresponding by index. + * @param _oldComponentsAuctionParams The auction params for the old components, corresponding by index. + * @return aggregateComponents Combined array of current and new components, without duplicates. + * @return aggregateAuctionParams Combined array of old and new component auction params, without duplicates. + */ + function _aggregateComponentsAndAuctionParams( + address[] memory _currentComponents, + address[] calldata _newComponents, + AuctionExecutionParams[] memory _newComponentsAuctionParams, + AuctionExecutionParams[] memory _oldComponentsAuctionParams + ) + internal + view + returns (address[] memory aggregateComponents, AuctionExecutionParams[] memory aggregateAuctionParams) + { + // Validate input arrays: new components and new auction params must have the same length, + // old components and old auction params must have the same length. + require(_newComponents.length == _newComponentsAuctionParams.length, "New components and params length mismatch"); + require(_currentComponents.length == _oldComponentsAuctionParams.length, "Old components and params length mismatch"); + + // Aggregate the current components and new components + aggregateComponents = _currentComponents.extend(_newComponents); + + // Ensure there are no duplicates in the aggregated components + require(!aggregateComponents.hasDuplicate(), "Cannot have duplicate components"); + + // Aggregate and validate the old and new auction params + aggregateAuctionParams = _concatAndValidateAuctionParams(_oldComponentsAuctionParams, _newComponentsAuctionParams); + } + + /** + * @dev Validates that the component is an eligible target for bids during the rebalance. Bids cannot be placed explicitly + * on the rebalance quote asset, it may only be implicitly bid by being the quote asset for other component bids. + * + * @param _setToken The SetToken instance involved in the rebalance. + * @param _component The component to be validated. + * @param _quoteAsset The ERC20 token expected to be used as the quote asset by the bidder + * @param _componentAmount The amount of component in the bid. + */ + function _validateBidTargets( + ISetToken _setToken, + IERC20 _component, + IERC20 _quoteAsset, + uint256 _componentAmount + ) + internal + view + { + IERC20 quoteAsset = rebalanceInfo[_setToken].quoteAsset; + // Ensure that the component is not the quote asset, as it cannot be explicitly bid on. + require(_component != quoteAsset, "Cannot bid explicitly on Quote Asset"); + + // Ensure that the auction quote asset matches the quote asset expected by the bidder. + require(_quoteAsset == quoteAsset, "Quote asset mismatch"); + + // Ensure that the component is part of the rebalance. + require(rebalanceInfo[_setToken].rebalanceComponents.contains(address(_component)), "Component not part of rebalance"); + + // Ensure that the SetToken doesn't have an external position for the component. + require(!_setToken.hasExternalPosition(address(_component)), "External positions not allowed"); + + // Ensure that the rebalance is in progress. + require(!_isRebalanceDurationElapsed(_setToken), "Rebalance must be in progress"); + + // Ensure that the component amount is greater than zero. + require(_componentAmount > 0, "Component amount must be > 0"); + } + + /** + * @dev Creates and returns a BidInfo struct. The function reverts if the auction target has already been met. + * + * @param _setToken The SetToken instance involved in the rebalance. + * @param _component The component to bid on. + * @param _componentQuantity The amount of component in the bid. + * @param _quoteQuantityLimit The max/min amount of quote asset to be spent/received during the bid. + * @param _isSellAuction The direction of the auction expected by the bidder + * + * @return bidInfo Struct containing data for the bid. + */ + function _createBidInfo( + ISetToken _setToken, + IERC20 _component, + uint256 _componentQuantity, + uint256 _quoteQuantityLimit, + bool _isSellAuction + ) + internal + view + returns (BidInfo memory bidInfo) + { + // Populate the bid info structure with basic information. + bidInfo.setToken = _setToken; + bidInfo.setTotalSupply = _setToken.totalSupply(); + bidInfo.priceAdapter = _getAuctionPriceAdapter(_setToken, _component); + bidInfo.priceAdapterConfigData = executionInfo[_setToken][_component].priceAdapterConfigData; + + // Calculate the auction size and direction. + (bidInfo.isSellAuction, bidInfo.auctionQuantity) = _calculateAuctionSizeAndDirection( + _setToken, + _component, + bidInfo.setTotalSupply + ); + + // Ensure that the auction direction matches the direction expected by the bidder. + require(bidInfo.isSellAuction == _isSellAuction, "Auction direction mismatch"); + + // Settle the auction if the component quantity is max uint256. + // Ensure that the component quantity in the bid does not exceed the available auction quantity. + if (_componentQuantity == type(uint256).max) { + _componentQuantity = bidInfo.auctionQuantity; + } else { + require(_componentQuantity <= bidInfo.auctionQuantity, "Bid size exceeds auction quantity"); + } + + // Set the sendToken and receiveToken based on the auction type (sell or buy). + (bidInfo.sendToken, bidInfo.receiveToken) = _getSendAndReceiveTokens(bidInfo.isSellAuction, _setToken, _component); + + // Retrieve the current price for the component. + bidInfo.componentPrice = bidInfo.priceAdapter.getPrice( + address(_setToken), + address(_component), + _componentQuantity, + block.timestamp.sub(rebalanceInfo[_setToken].rebalanceStartTime), + rebalanceInfo[_setToken].rebalanceDuration, + bidInfo.priceAdapterConfigData + ); + + // Calculate the quantity of quote asset involved in the bid. + uint256 quoteAssetQuantity = _calculateQuoteAssetQuantity( + bidInfo.isSellAuction, + _componentQuantity, + bidInfo.componentPrice + ); + + // Store pre-bid token balances for later use. + bidInfo.preBidTokenSentBalance = bidInfo.sendToken.balanceOf(address(_setToken)); + bidInfo.preBidTokenReceivedBalance = bidInfo.receiveToken.balanceOf(address(_setToken)); + + // Validate quote asset quantity against bidder's limit. + _validateQuoteAssetQuantity( + bidInfo.isSellAuction, + quoteAssetQuantity, + _quoteQuantityLimit, + bidInfo.preBidTokenSentBalance + ); + + // Calculate quantities sent and received by the Set during the bid. + (bidInfo.quantitySentBySet, bidInfo.quantityReceivedBySet) = _calculateQuantitiesForBid( + bidInfo.isSellAuction, + _componentQuantity, + quoteAssetQuantity + ); + } + + /** + * @notice Determines tokens involved in the bid based on auction type. + * @param isSellAuction Is the auction a sell type. + * @param _setToken The SetToken involved in the rebalance. + * @param _component The component involved in the auction. + * @return The tokens to send and receive in the bid. + */ + function _getSendAndReceiveTokens(bool isSellAuction, ISetToken _setToken, IERC20 _component) private view returns (IERC20, IERC20) { + return isSellAuction ? (_component, IERC20(rebalanceInfo[_setToken].quoteAsset)) : (IERC20(rebalanceInfo[_setToken].quoteAsset), _component); + } + + /** + * @notice Calculates the quantity of quote asset involved in the bid. + * @param isSellAuction Is the auction a sell type. + * @param _componentQuantity The amount of component in the bid. + * @param _componentPrice The price of the component. + * @return The quantity of quote asset in the bid. + */ + function _calculateQuoteAssetQuantity(bool isSellAuction, uint256 _componentQuantity, uint256 _componentPrice) private pure returns (uint256) { + return isSellAuction ? _componentQuantity.preciseMulCeil(_componentPrice) : _componentQuantity.preciseMul(_componentPrice); + } + + /** + * @notice Validates the quote asset quantity against bidder's limit. + * @param isSellAuction Is the auction a sell type. + * @param quoteAssetQuantity The quantity of quote asset in the bid. + * @param _quoteQuantityLimit The max/min amount of quote asset to be spent/received. + * @param preBidTokenSentBalance The balance of tokens sent before the bid. + */ + function _validateQuoteAssetQuantity(bool isSellAuction, uint256 quoteAssetQuantity, uint256 _quoteQuantityLimit, uint256 preBidTokenSentBalance) private pure { + if (isSellAuction) { + require(quoteAssetQuantity <= _quoteQuantityLimit, "Quote asset quantity exceeds limit"); + } else { + require(quoteAssetQuantity >= _quoteQuantityLimit, "Quote asset quantity below limit"); + require(quoteAssetQuantity <= preBidTokenSentBalance, "Insufficient quote asset balance"); + } + } + + /** + * @notice Calculates the quantities sent and received by the Set during the bid. + * @param isSellAuction Is the auction a sell type. + * @param _componentQuantity The amount of component in the bid. + * @param quoteAssetQuantity The quantity of quote asset in the bid. + * @return The quantities of tokens sent and received by the Set. + */ + function _calculateQuantitiesForBid(bool isSellAuction, uint256 _componentQuantity, uint256 quoteAssetQuantity) private pure returns (uint256, uint256) { + return isSellAuction ? (_componentQuantity, quoteAssetQuantity) : (quoteAssetQuantity, _componentQuantity); + } + + /** + * @dev Calculates the size and direction of the auction for a given component. Determines whether the component + * is being bought or sold and the quantity required to settle the auction. + * + * @param _setToken The SetToken instance to be rebalanced. + * @param _component The component whose auction size and direction need to be calculated. + * @param _totalSupply The total supply of the SetToken. + * + * @return isSellAuction Indicates if this is a sell auction (true) or a buy auction (false). + * @return maxComponentQty The maximum quantity of the component to be exchanged to settle the auction. + */ + function _calculateAuctionSizeAndDirection( + ISetToken _setToken, + IERC20 _component, + uint256 _totalSupply + ) + internal + view + returns (bool isSellAuction, uint256 maxComponentQty) + { + uint256 protocolFee = controller.getModuleFee(address(this), AUCTION_MODULE_V1_PROTOCOL_FEE_INDEX); + + // Retrieve the current and target units, and notional amounts of the component + ( + uint256 currentUnit, + uint256 targetUnit, + uint256 currentNotional, + uint256 targetNotional + ) = _getUnitsAndNotionalAmounts(_setToken, _component, _totalSupply); + + // Ensure that the current unit and target unit are not the same + require(currentUnit != targetUnit, "Target already met"); + + // Determine whether the component is being sold (sendToken) or bought + isSellAuction = targetNotional < currentNotional; + + // Calculate the max quantity of the component to be exchanged. If buying, account for the protocol fees. + maxComponentQty = isSellAuction + ? currentNotional.sub(targetNotional) + : targetNotional.sub(currentNotional).preciseDiv(PreciseUnitMath.preciseUnit().sub(protocolFee)); + } + + /** + * @dev Executes the bid by performing token transfers. + * + * @param _bidInfo Struct containing the bid information. + */ + function _executeBid( + BidInfo memory _bidInfo + ) + internal + { + // Transfer the received tokens from the sender to the SetToken. + transferFrom( + _bidInfo.receiveToken, + msg.sender, + address(_bidInfo.setToken), + _bidInfo.quantityReceivedBySet + ); + + // Invoke the transfer of the sent tokens from the SetToken to the sender. + _bidInfo.setToken.strictInvokeTransfer( + address(_bidInfo.sendToken), + msg.sender, + _bidInfo.quantitySentBySet + ); + } + + /** + * @dev Calculates the protocol fee based on the tokens received during the bid and transfers it + * from the SetToken to the protocol recipient. + * + * @param _bidInfo Struct containing information related to the bid. + * + * @return uint256 The amount of the received tokens taken as a protocol fee. + */ + function _accrueProtocolFee(BidInfo memory _bidInfo) internal returns (uint256) { + IERC20 receiveToken = IERC20(_bidInfo.receiveToken); + ISetToken setToken = _bidInfo.setToken; + + // Calculate the amount of tokens exchanged during the bid. + uint256 exchangedQuantity = receiveToken.balanceOf(address(setToken)) + .sub(_bidInfo.preBidTokenReceivedBalance); + + // Calculate the protocol fee. + uint256 protocolFee = getModuleFee(AUCTION_MODULE_V1_PROTOCOL_FEE_INDEX, exchangedQuantity); + + // Transfer the protocol fee from the SetToken to the protocol recipient. + payProtocolFeeFromSetToken(setToken, address(_bidInfo.receiveToken), protocolFee); + + return protocolFee; + } + + /** + * @dev Updates the positions of the SetToken after the bid. This function should be called + * after the protocol fees have been accrued. It calculates and returns the net amount of tokens + * used and received during the bid. + * + * @param _bidInfo Struct containing information related to the bid. + * + * @return uint256 The net amount of send tokens used in the bid. + * @return uint256 The net amount of receive tokens after accounting for protocol fees. + */ + function _updatePositionState(BidInfo memory _bidInfo) + internal + returns (uint256, uint256) + { + ISetToken setToken = _bidInfo.setToken; + + // Calculate and update positions for send tokens. + (uint256 postBidSendTokenBalance,,) = setToken.calculateAndEditDefaultPosition( + address(_bidInfo.sendToken), + _bidInfo.setTotalSupply, + _bidInfo.preBidTokenSentBalance + ); + + // Calculate and update positions for receive tokens. + (uint256 postBidReceiveTokenBalance,,) = setToken.calculateAndEditDefaultPosition( + address(_bidInfo.receiveToken), + _bidInfo.setTotalSupply, + _bidInfo.preBidTokenReceivedBalance + ); + + // Calculate the net amount of tokens used and received. + uint256 netSendAmount = _bidInfo.preBidTokenSentBalance.sub(postBidSendTokenBalance); + uint256 netReceiveAmount = postBidReceiveTokenBalance.sub(_bidInfo.preBidTokenReceivedBalance); + + return (netSendAmount, netReceiveAmount); + } + + /** + * @dev Retrieves the unit and notional amount values for the current position and target. + * These are necessary to calculate the bid size and direction. + * + * @param _setToken Instance of the SetToken to be rebalanced. + * @param _component The component to calculate notional amounts for. + * @param _totalSupply SetToken total supply. + * + * @return uint256 Current default position real unit of the component. + * @return uint256 Normalized unit of the bid target. + * @return uint256 Current notional amount, based on total notional amount of SetToken default position. + * @return uint256 Target notional amount, based on total SetToken supply multiplied by targetUnit. + */ + function _getUnitsAndNotionalAmounts( + ISetToken _setToken, + IERC20 _component, + uint256 _totalSupply + ) + internal + view + returns (uint256, uint256, uint256, uint256) + { + uint256 currentUnit = _getDefaultPositionRealUnit(_setToken, _component); + uint256 targetUnit = _getNormalizedTargetUnit(_setToken, _component); + + uint256 currentNotionalAmount = _totalSupply.getDefaultTotalNotional(currentUnit); + uint256 targetNotionalAmount = _totalSupply.preciseMulCeil(targetUnit); + + return (currentUnit, targetUnit, currentNotionalAmount, targetNotionalAmount); + } + + /** + * @dev Checks if all target units for components have been met. + * + * @param _setToken Instance of the SetToken to be rebalanced. + * + * @return bool True if all component's target units have been met; false otherwise. + */ + function _allTargetsMet(ISetToken _setToken) internal view returns (bool) { + address[] memory rebalanceComponents = rebalanceInfo[_setToken].rebalanceComponents; + + for (uint256 i = 0; i < rebalanceComponents.length; i++) { + if (_targetUnmet(_setToken, rebalanceComponents[i])) { + return false; + } + } + + return true; + } + + /** + * @dev Determines if the target units for a given component are met. Takes into account minor rounding errors. + * WETH is not checked as it is allowed to float around its target. + * + * @param _setToken Instance of the SetToken to be rebalanced. + * @param _component Component whose target is evaluated. + * + * @return bool True if component's target units are met; false otherwise. + */ + function _targetUnmet( + ISetToken _setToken, + address _component + ) + internal + view + returns(bool) + { + if (_component == address(rebalanceInfo[_setToken].quoteAsset)) return false; + + uint256 normalizedTargetUnit = _getNormalizedTargetUnit(_setToken, IERC20(_component)); + uint256 currentUnit = _getDefaultPositionRealUnit(_setToken, IERC20(_component)); + + return (normalizedTargetUnit > 0) + ? !normalizedTargetUnit.approximatelyEquals(currentUnit, 1) + : normalizedTargetUnit != currentUnit; + } + + /** + * @dev Retrieves the SetToken's default position real unit. + * + * @param _setToken Instance of the SetToken. + * @param _component Component to fetch the default position for. + * + * @return uint256 Real unit position. + */ + function _getDefaultPositionRealUnit( + ISetToken _setToken, + IERC20 _component + ) + internal + view + returns (uint256) + { + return _setToken.getDefaultPositionRealUnit(address(_component)).toUint256(); + } + + /** + * @dev Calculates and retrieves the normalized target unit value for a given component. + * + * @param _setToken Instance of the SetToken. + * @param _component Component whose normalized target unit is required. + * + * @return uint256 Normalized target unit of the component. + */ + function _getNormalizedTargetUnit( + ISetToken _setToken, + IERC20 _component + ) + internal + view + returns(uint256) + { + // (targetUnit * current position multiplier) / position multiplier at the start of rebalance + return executionInfo[_setToken][_component] + .targetUnit + .mul(_setToken.positionMultiplier().toUint256()) + .div(rebalanceInfo[_setToken].positionMultiplier); + } + + /** + * @dev Checks if the specified address is allowed to call the bid for the SetToken. + * If `anyoneBid` is set to true, any address is allowed, otherwise the address + * must be explicitly approved. + * + * @param _setToken Instance of the SetToken to be rebalanced. + * @param _bidder Address of the bidder. + * + * @return bool True if the address is allowed to bid, false otherwise. + */ + function _isAllowedBidder( + ISetToken _setToken, + address _bidder + ) + internal + view + returns (bool) + { + BidPermissionInfo storage permissions = permissionInfo[_setToken]; + return permissions.isAnyoneAllowedToBid || permissions.bidAllowList[_bidder]; + } + + /** + * @dev Updates the permission status of a bidder and maintains a history. This function adds + * the bidder to the history if being permissioned, and removes it if being unpermissioned. + * Ensures that AddressArrayUtils does not throw by verifying the presence of the address + * before removal. + * + * @param _setToken Instance of the SetToken. + * @param _bidder Address of the bidder whose permission is being updated. + * @param _status The permission status being set (true for permissioned, false for unpermissioned). + */ + function _updateBiddersHistory( + ISetToken _setToken, + address _bidder, + bool _status + ) + internal + { + if (_status && !permissionInfo[_setToken].biddersHistory.contains(_bidder)) { + permissionInfo[_setToken].biddersHistory.push(_bidder); + } else if(!_status && permissionInfo[_setToken].biddersHistory.contains(_bidder)) { + permissionInfo[_setToken].biddersHistory.removeStorage(_bidder); + } + } + + /** + * @dev Checks if the rebalance duration has elapsed for the given SetToken. + * + * @param _setToken The SetToken whose rebalance duration is being checked. + * @return bool True if the rebalance duration has elapsed; false otherwise. + */ + function _isRebalanceDurationElapsed(ISetToken _setToken) internal view returns (bool) { + RebalanceInfo storage rebalance = rebalanceInfo[_setToken]; + return (rebalance.rebalanceStartTime.add(rebalance.rebalanceDuration)) <= block.timestamp; + } + + /** + * @dev Checks if the conditions for early unlock are met. + * + * @param _setToken The SetToken being checked. + * @return bool True if early unlock conditions are met; false otherwise. + */ + function _canUnlockEarly(ISetToken _setToken) internal view returns (bool) { + RebalanceInfo storage rebalance = rebalanceInfo[_setToken]; + return _allTargetsMet(_setToken) && _isQuoteAssetExcessOrAtTarget(_setToken) && rebalance.raiseTargetPercentage == 0; + } + + /** + * @dev Checks if the quote asset is in excess or at target. + * + * @param _setToken The SetToken being checked. + * @return bool True if the quote asset is in excess or at target; false otherwise. + */ + function _isQuoteAssetExcessOrAtTarget(ISetToken _setToken) internal view returns (bool) { + RebalanceInfo storage rebalance = rebalanceInfo[_setToken]; + bool isExcess = _getDefaultPositionRealUnit(_setToken, rebalance.quoteAsset) > _getNormalizedTargetUnit(_setToken, rebalance.quoteAsset); + bool isAtTarget = _getDefaultPositionRealUnit(_setToken, rebalance.quoteAsset).approximatelyEquals(_getNormalizedTargetUnit(_setToken, rebalance.quoteAsset), 1); + return isExcess || isAtTarget; + } + + /** + * @dev Checks if the conditions to raise asset targets are met. + * + * @param _setToken The SetToken being checked. + * @return bool True if conditions to raise asset targets are met; false otherwise. + */ + function _canRaiseAssetTargets(ISetToken _setToken) internal view returns (bool) { + RebalanceInfo storage rebalance = rebalanceInfo[_setToken]; + bool isQuoteAssetExcess = _getDefaultPositionRealUnit(_setToken, rebalance.quoteAsset) > _getNormalizedTargetUnit(_setToken, rebalance.quoteAsset); + return _allTargetsMet(_setToken) && isQuoteAssetExcess; + } + + /** + * @dev Retrieves the price adapter address for a component after verifying its existence + * in the IntegrationRegistry. This function ensures the validity of the adapter during a bid. + * + * @param _setToken Instance of the SetToken to be rebalanced. + * @param _component Component whose price adapter is to be fetched. + * + * @return IAuctionPriceAdapter The price adapter's address. + */ + function _getAuctionPriceAdapter( + ISetToken _setToken, + IERC20 _component + ) + internal + view + returns(IAuctionPriceAdapterV1) + { + return IAuctionPriceAdapterV1(getAndValidateAdapter(executionInfo[_setToken][_component].priceAdapterName)); + } + + /** + * @dev Concatenates two arrays of AuctionExecutionParams after validating them. + * + * @param _oldAuctionParams The first array of AuctionExecutionParams. + * @param _newAuctionParams The second array of AuctionExecutionParams. + * @return concatenatedParams The concatenated array of AuctionExecutionParams. + */ + function _concatAndValidateAuctionParams( + AuctionExecutionParams[] memory _oldAuctionParams, + AuctionExecutionParams[] memory _newAuctionParams + ) + internal + view + returns (AuctionExecutionParams[] memory concatenatedParams) + { + uint256 oldLength = _oldAuctionParams.length; + uint256 newLength = _newAuctionParams.length; + + // Initialize the concatenated array with the combined size of the input arrays + concatenatedParams = new AuctionExecutionParams[](oldLength + newLength); + + // Copy and validate the old auction params + for (uint256 i = 0; i < oldLength; i++) { + _validateAuctionExecutionPriceParams(_oldAuctionParams[i]); + concatenatedParams[i] = _oldAuctionParams[i]; + } + + // Append and validate the new auction params + for (uint256 j = 0; j < newLength; j++) { + require(_newAuctionParams[j].targetUnit > 0, "New component target unit must be greater than 0"); + _validateAuctionExecutionPriceParams(_newAuctionParams[j]); + concatenatedParams[oldLength + j] = _newAuctionParams[j]; + } + + return concatenatedParams; + } + + /** + * @dev Validates the given auction execution price adapter params. + * + * @param auctionParams The auction parameters to validate. + */ + function _validateAuctionExecutionPriceParams(AuctionExecutionParams memory auctionParams) internal view { + IAuctionPriceAdapterV1 adapter = IAuctionPriceAdapterV1(getAndValidateAdapter(auctionParams.priceAdapterName)); + require(adapter.isPriceAdapterConfigDataValid(auctionParams.priceAdapterConfigData), "Price adapter config data invalid"); + } + + /* ============== Modifier Helpers =============== + * Internal functions used to reduce bytecode size + */ + + /* + * Bidder must be permissioned for SetToken + */ + function _validateOnlyAllowedBidder(ISetToken _setToken) internal view { + require(_isAllowedBidder(_setToken, msg.sender), "Address not permitted to bid"); + } +} diff --git a/external/contracts/set/ConstantPriceAdapter.sol b/external/contracts/set/ConstantPriceAdapter.sol new file mode 100644 index 00000000..a750d39b --- /dev/null +++ b/external/contracts/set/ConstantPriceAdapter.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity 0.8.17; + +/** + * @title ConstantPriceAdapter + * @author Index Coop + * @notice Price adapter contract for AuctionRebalanceModuleV1 that returns a constant price. + * The rate of change is zero. + * Price formula: price = initialPrice + */ +contract ConstantPriceAdapter { + /** + * @dev Calculates and returns the constant price. + * + * @param _priceAdapterConfigData Encoded bytes representing the constant price. + * + * @return price The constant price decoded from _priceAdapterConfigData. + */ + function getPrice( + address /* _setToken */, + address /* _component */, + uint256 /* _componentQuantity */, + uint256 /* _timeElapsed */, + uint256 /* _duration */, + bytes memory _priceAdapterConfigData + ) + external + pure + returns (uint256 price) + { + price = getDecodedData(_priceAdapterConfigData); + require(price > 0, "ConstantPriceAdapter: Price must be greater than 0"); + } + + /** + * @notice Returns true if the price adapter configuration data is valid. + * + * @param _priceAdapterConfigData Encoded bytes representing the constant price. + * + * @return isValid True if the constant price is greater than 0, False otherwise. + */ + function isPriceAdapterConfigDataValid( + bytes memory _priceAdapterConfigData + ) + external + pure + returns (bool isValid) + { + uint256 price = getDecodedData(_priceAdapterConfigData); + isValid = price > 0; + } + + /** + * @notice Encodes the constant price into bytes. + * + * @param _price The constant price in base units. + * + * @return Encoded bytes representing the constant price. + */ + function getEncodedData(uint256 _price) external pure returns (bytes memory) { + return abi.encode(_price); + } + + /** + * @dev Decodes the constant price from the provided bytes. + * + * @param _data Encoded bytes representing the constant price. + * + * @return The constant price decoded from bytes in base units. + */ + function getDecodedData(bytes memory _data) public pure returns (uint256) { + return abi.decode(_data, (uint256)); + } +} diff --git a/test/adapters/auctionRebalanceExtension.spec.ts b/test/adapters/auctionRebalanceExtension.spec.ts new file mode 100644 index 00000000..5d1fe400 --- /dev/null +++ b/test/adapters/auctionRebalanceExtension.spec.ts @@ -0,0 +1,556 @@ +import "module-alias/register"; + +import { Address, Account } from "@utils/types"; +import { ADDRESS_ZERO, ZERO } from "@utils/constants"; +import { AuctionRebalanceExtension, BaseManagerV2, ConstantPriceAdapter } from "@utils/contracts/index"; +import { SetToken } from "@utils/contracts/setV2"; +import DeployHelper from "@utils/deploys"; +import { + addSnapshotBeforeRestoreAfterEach, + ether, + getAccounts, + getSetFixture, + getWaffleExpect, + bitcoin, + usdc, + getTransactionTimestamp, + increaseTimeAsync, +} from "@utils/index"; +import { SetFixture } from "@utils/fixtures"; +import { BigNumber, ContractTransaction } from "ethers"; + +const expect = getWaffleExpect(); + +describe("AuctionRebalanceExtension", () => { + let owner: Account; + let methodologist: Account; + let operator: Account; + let approvedCaller: Account; + + let setV2Setup: SetFixture; + + let deployer: DeployHelper; + let setToken: SetToken; + + let baseManagerV2: BaseManagerV2; + let auctionExtension: AuctionRebalanceExtension; + + let priceAdapter: ConstantPriceAdapter; + + before(async () => { + [ + owner, + methodologist, + operator, + approvedCaller, + ] = await getAccounts(); + + deployer = new DeployHelper(owner.wallet); + + setV2Setup = getSetFixture(owner.address); + await setV2Setup.initialize(); + + priceAdapter = await deployer.setV2.deployConstantPriceAdapter(); + + await setV2Setup.integrationRegistry.addIntegration( + setV2Setup.auctionModule.address, + "ConstantPriceAdapter", + priceAdapter.address + ); + + setToken = await setV2Setup.createSetToken( + [setV2Setup.dai.address, setV2Setup.wbtc.address, setV2Setup.weth.address], + [ether(100), bitcoin(.01), ether(.1)], + [setV2Setup.auctionModule.address, setV2Setup.issuanceModule.address] + ); + + await setV2Setup.issuanceModule.initialize( + setToken.address, + ADDRESS_ZERO + ); + + // Deploy BaseManager + baseManagerV2 = await deployer.manager.deployBaseManagerV2( + setToken.address, + operator.address, + methodologist.address + ); + await baseManagerV2.connect(methodologist.wallet).authorizeInitialization(); + }); + + addSnapshotBeforeRestoreAfterEach(); + + describe("#constructor", async () => { + let subjectManager: Address; + let subjectAuctionRebalanceModule: Address; + + beforeEach(async () => { + subjectManager = baseManagerV2.address; + subjectAuctionRebalanceModule = setV2Setup.auctionModule.address; + }); + + async function subject(): Promise { + return await deployer.extensions.deployAuctionRebalanceExtension( + subjectManager, + subjectAuctionRebalanceModule + ); + } + + it("should set the correct SetToken address", async () => { + const auctionExtension = await subject(); + + const actualToken = await auctionExtension.setToken(); + expect(actualToken).to.eq(setToken.address); + }); + + it("should set the correct manager address", async () => { + const auctionExtension = await subject(); + + const actualManager = await auctionExtension.manager(); + expect(actualManager).to.eq(baseManagerV2.address); + }); + + it("should set the correct auction rebalance module address", async () => { + const auctionExtension = await subject(); + + const actualAuctionRebalanceModule = await auctionExtension.auctionModule(); + expect(actualAuctionRebalanceModule).to.eq(subjectAuctionRebalanceModule); + }); + }); + + context("when auction rebalance extension is deployed and module needs to be initialized", async () => { + beforeEach(async () => { + auctionExtension = await deployer.extensions.deployAuctionRebalanceExtension( + baseManagerV2.address, + setV2Setup.auctionModule.address + ); + + await baseManagerV2.connect(operator.wallet).addExtension(auctionExtension.address); + + await auctionExtension.connect(operator.wallet).updateCallerStatus([approvedCaller.address], [true]); + + // Transfer ownership to BaseManager + await setToken.setManager(baseManagerV2.address); + }); + + describe("#initialize", async () => { + let subjectCaller: Account; + + beforeEach(async () => { + subjectCaller = operator; + }); + + async function subject(): Promise { + return await auctionExtension.connect(subjectCaller.wallet).initialize(); + } + + it("should initialize AuctionRebalanceModule", async () => { + await subject(); + + const isInitialized = await setToken.isInitializedModule(setV2Setup.auctionModule.address); + expect(isInitialized).to.be.true; + }); + + describe("when the operator is not the caller", async () => { + beforeEach(async () => { + subjectCaller = approvedCaller; + }); + + it("should revert", async () => { + await expect(subject()).to.be.revertedWith("Must be operator"); + }); + }); + }); + + context("when auction rebalance extension is deployed and system fully set up", async () => { + beforeEach(async () => { + await auctionExtension.connect(operator.wallet).initialize(); + }); + + describe("#startRebalance", async () => { + let subjectQuoteAsset: Address; + let subjectOldComponents: Address[]; + let subjectNewComponents: Address[]; + let subjectNewComponentsAuctionParams: any[]; + let subjectOldComponentsAuctionParams: any[]; + let subjectShouldLockSetToken: boolean; + let subjectRebalanceDuration: BigNumber; + let subjectPositionMultiplier: BigNumber; + let subjectCaller: Account; + + beforeEach(async () => { + subjectQuoteAsset = setV2Setup.weth.address; + + subjectOldComponents = [setV2Setup.dai.address, setV2Setup.wbtc.address, setV2Setup.weth.address]; + subjectNewComponents = [setV2Setup.usdc.address]; + + subjectNewComponentsAuctionParams = [ + { + targetUnit: usdc(100), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: await priceAdapter.getEncodedData(ether(0.005)), + }, + ]; + + subjectOldComponentsAuctionParams = [ + { + targetUnit: ether(50), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: await priceAdapter.getEncodedData(ether(0.005)), + }, + { + targetUnit: bitcoin(.01), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: await priceAdapter.getEncodedData(ether(0.005)), + }, + { + targetUnit: ether(.1), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: await priceAdapter.getEncodedData(ether(0.005)), + }, + ]; + + subjectShouldLockSetToken = true; + subjectRebalanceDuration = BigNumber.from(86400); + subjectPositionMultiplier = ether(.999); + subjectCaller = operator; + }); + + async function subject(): Promise { + return await auctionExtension.connect(subjectCaller.wallet).startRebalance( + subjectQuoteAsset, + subjectOldComponents, + subjectNewComponents, + subjectNewComponentsAuctionParams, + subjectOldComponentsAuctionParams, + subjectShouldLockSetToken, + subjectRebalanceDuration, + subjectPositionMultiplier + ); + } + + it("should set the auction execution params correctly", async () => { + await subject(); + + const aggregateComponents = [...subjectOldComponents, ...subjectNewComponents]; + const aggregateAuctionParams = [...subjectOldComponentsAuctionParams, ...subjectNewComponentsAuctionParams]; + + for (let i = 0; i < aggregateAuctionParams.length; i++) { + const executionInfo = await setV2Setup.auctionModule.executionInfo(setToken.address, aggregateComponents[i]); + expect(executionInfo.targetUnit).to.eq(aggregateAuctionParams[i].targetUnit); + expect(executionInfo.priceAdapterName).to.eq(aggregateAuctionParams[i].priceAdapterName); + expect(executionInfo.priceAdapterConfigData).to.eq(aggregateAuctionParams[i].priceAdapterConfigData); + } + }); + + it("should set the rebalance info correctly", async () => { + const txnTimestamp = await getTransactionTimestamp(subject()); + + const rebalanceInfo = await setV2Setup.auctionModule.rebalanceInfo(setToken.address); + + expect(rebalanceInfo.quoteAsset).to.eq(subjectQuoteAsset); + expect(rebalanceInfo.rebalanceStartTime).to.eq(txnTimestamp); + expect(rebalanceInfo.rebalanceDuration).to.eq(subjectRebalanceDuration); + expect(rebalanceInfo.positionMultiplier).to.eq(subjectPositionMultiplier); + expect(rebalanceInfo.raiseTargetPercentage).to.eq(ZERO); + + const rebalanceComponents = await setV2Setup.auctionModule.getRebalanceComponents(setToken.address); + const aggregateComponents = [...subjectOldComponents, ...subjectNewComponents]; + + for (let i = 0; i < rebalanceComponents.length; i++) { + expect(rebalanceComponents[i]).to.eq(aggregateComponents[i]); + } + }); + + describe("when there are no new components", async () => { + beforeEach(async () => { + subjectNewComponents = []; + subjectNewComponentsAuctionParams = []; + }); + + it("should set the auction execution params correctly", async () => { + await subject(); + + for (let i = 0; i < subjectOldComponents.length; i++) { + const executionInfo = await setV2Setup.auctionModule.executionInfo(setToken.address, subjectOldComponents[i]); + expect(executionInfo.targetUnit).to.eq(subjectOldComponentsAuctionParams[i].targetUnit); + expect(executionInfo.priceAdapterName).to.eq(subjectOldComponentsAuctionParams[i].priceAdapterName); + expect(executionInfo.priceAdapterConfigData).to.eq(subjectOldComponentsAuctionParams[i].priceAdapterConfigData); + } + }); + + it("should set the rebalance info correctly", async () => { + const txnTimestamp = await getTransactionTimestamp(subject()); + + const rebalanceInfo = await setV2Setup.auctionModule.rebalanceInfo(setToken.address); + + expect(rebalanceInfo.quoteAsset).to.eq(subjectQuoteAsset); + expect(rebalanceInfo.rebalanceStartTime).to.eq(txnTimestamp); + expect(rebalanceInfo.rebalanceDuration).to.eq(subjectRebalanceDuration); + expect(rebalanceInfo.positionMultiplier).to.eq(subjectPositionMultiplier); + expect(rebalanceInfo.raiseTargetPercentage).to.eq(ZERO); + + const rebalanceComponents = await setV2Setup.auctionModule.getRebalanceComponents(setToken.address); + for (let i = 0; i < rebalanceComponents.length; i++) { + expect(rebalanceComponents[i]).to.eq(subjectOldComponents[i]); + } + }); + }); + + describe("when old components are passed in different order", async () => { + beforeEach(async () => { + subjectOldComponents = [setV2Setup.dai.address, setV2Setup.weth.address, setV2Setup.wbtc.address]; + }); + + it("should revert", async () => { + await expect(subject()).to.be.revertedWith("Input old components array must match the current components array."); + }); + }); + + describe("when old components array is shorter than current components array", async () => { + beforeEach(async () => { + subjectOldComponents = [setV2Setup.dai.address, setV2Setup.wbtc.address]; + subjectOldComponentsAuctionParams = [ + { + targetUnit: ether(50), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: await priceAdapter.getEncodedData(ether(0.005)), + }, + { + targetUnit: bitcoin(.01), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: await priceAdapter.getEncodedData(ether(0.005)), + }, + ]; + }); + + it("should revert", async () => { + await expect(subject()).to.be.revertedWith("Old components length must match the current components length."); + }); + }); + + describe("when old components array is longer than current components array", async () => { + beforeEach(async () => { + const price = await priceAdapter.getEncodedData(ether(1)); + subjectOldComponents = [setV2Setup.dai.address, setV2Setup.wbtc.address, setV2Setup.weth.address, setV2Setup.usdc.address]; + subjectOldComponentsAuctionParams = [ + { + targetUnit: ether(50), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: price, + }, + { + targetUnit: bitcoin(.01), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: price, + }, + { + targetUnit: ether(.1), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: price, + }, + { + targetUnit: usdc(100), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: price, + }, + ]; + }); + + it("should revert", async () => { + await expect(subject()).to.be.revertedWith("Old components length must match the current components length."); + }); + }); + + describe("when not all old components have an entry", async () => { + beforeEach(async () => { + subjectOldComponents = [setV2Setup.dai.address, setV2Setup.wbtc.address, setV2Setup.usdc.address]; + }); + + it("should revert", async () => { + await expect(subject()).to.be.revertedWith("Input old components array must match the current components array."); + }); + }); + + describe("when the caller is not the operator", async () => { + beforeEach(async () => { + subjectCaller = approvedCaller; + }); + + it("should revert", async () => { + await expect(subject()).to.be.revertedWith("Must be operator"); + }); + }); + }); + + describe("#unlock", async () => { + let subjectCaller: Account; + + beforeEach(async () => { + const oldComponents = [setV2Setup.dai.address, setV2Setup.wbtc.address, setV2Setup.weth.address]; + + const oldComponentsAuctionParams = [ + { + targetUnit: ether(100), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: await priceAdapter.getEncodedData(ether(0.005)), + }, + { + targetUnit: bitcoin(.01), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: await priceAdapter.getEncodedData(ether(0.005)), + }, + { + targetUnit: ether(.1), + priceAdapterName: "ConstantPriceAdapter", + priceAdapterConfigData: await priceAdapter.getEncodedData(ether(0.005)), + }, + ]; + + await auctionExtension.connect(operator.wallet).startRebalance( + setV2Setup.weth.address, + oldComponents, + [], + [], + oldComponentsAuctionParams, + true, + BigNumber.from(5), + ether(.999) + ); + + subjectCaller = operator; + }); + + async function subject(): Promise { + await increaseTimeAsync(BigNumber.from(6)); + return await auctionExtension.connect(subjectCaller.wallet).unlock(); + } + + it("should unlock the SetToken", async () => { + const isLockedBefore = await setToken.isLocked(); + expect(isLockedBefore).to.be.true; + + await subject(); + + const isLockedAfter = await setToken.isLocked(); + expect(isLockedAfter).to.be.false; + }); + + describe("when the caller is not the operator", async () => { + beforeEach(async () => { + subjectCaller = approvedCaller; + }); + + it("should revert", async () => { + await expect(subject()).to.be.revertedWith("Must be operator"); + }); + }); + }); + + describe("#setRaiseTargetPercentage", async () => { + let subjectRaiseTargetPercentage: BigNumber; + let subjectCaller: Account; + + beforeEach(async () => { + subjectRaiseTargetPercentage = ether(.001); + subjectCaller = operator; + }); + + async function subject(): Promise { + return await auctionExtension.connect(subjectCaller.wallet).setRaiseTargetPercentage( + subjectRaiseTargetPercentage, + ); + } + + it("should correctly set the raiseTargetPercentage", async () => { + await subject(); + + const actualRaiseTargetPercentage = (await setV2Setup.auctionModule.rebalanceInfo(setToken.address)).raiseTargetPercentage; + + expect(actualRaiseTargetPercentage).to.eq(subjectRaiseTargetPercentage); + }); + + describe("when the caller is not the operator", async () => { + beforeEach(async () => { + subjectCaller = approvedCaller; + }); + + it("should revert", async () => { + await expect(subject()).to.be.revertedWith("Must be operator"); + }); + }); + }); + + describe("#setBidderStatus", async () => { + let subjectBidders: Address[]; + let subjectStatuses: boolean[]; + let subjectCaller: Account; + + beforeEach(async () => { + subjectBidders = [methodologist.address]; + subjectStatuses = [true]; + subjectCaller = operator; + }); + + async function subject(): Promise { + return await auctionExtension.connect(subjectCaller.wallet).setBidderStatus( + subjectBidders, + subjectStatuses + ); + } + + it("should correctly set the bidder status", async () => { + await subject(); + + const isCaller = await setV2Setup.auctionModule.isAllowedBidder(setToken.address, subjectBidders[0]); + + expect(isCaller).to.be.true; + }); + + describe("when the caller is not the operator", async () => { + beforeEach(async () => { + subjectCaller = approvedCaller; + }); + + it("should revert", async () => { + await expect(subject()).to.be.revertedWith("Must be operator"); + }); + }); + }); + + describe("#setAnyoneBid", async () => { + let subjectStatus: boolean; + let subjectCaller: Account; + + beforeEach(async () => { + subjectStatus = true; + subjectCaller = operator; + }); + + async function subject(): Promise { + return await auctionExtension.connect(subjectCaller.wallet).setAnyoneBid( + subjectStatus + ); + } + + it("should correctly set anyone bid", async () => { + await subject(); + + const anyoneBid = await setV2Setup.auctionModule.permissionInfo(setToken.address); + + expect(anyoneBid).to.be.true; + }); + + describe("when the caller is not the operator", async () => { + beforeEach(async () => { + subjectCaller = approvedCaller; + }); + + it("should revert", async () => { + await expect(subject()).to.be.revertedWith("Must be operator"); + }); + }); + }); + }); + }); +}); diff --git a/utils/contracts/index.ts b/utils/contracts/index.ts index 4ae81600..655840ec 100644 --- a/utils/contracts/index.ts +++ b/utils/contracts/index.ts @@ -1,10 +1,12 @@ export { AaveLeverageStrategyExtension } from "../../typechain/AaveLeverageStrategyExtension"; export { AirdropExtension } from "../../typechain/AirdropExtension"; +export { AuctionRebalanceExtension } from "../../typechain/AuctionRebalanceExtension"; export { AirdropIssuanceHook } from "../../typechain/AirdropIssuanceHook"; export { BaseExtensionMock } from "../../typechain/BaseExtensionMock"; export { BaseManager } from "../../typechain/BaseManager"; export { BaseManagerV2 } from "../../typechain/BaseManagerV2"; export { ChainlinkAggregatorV3Mock } from "../../typechain/ChainlinkAggregatorV3Mock"; +export { ConstantPriceAdapter } from "../../typechain/ConstantPriceAdapter"; export { DebtIssuanceModule } from "../../typechain/DebtIssuanceModule"; export { BasicIssuanceModule } from "../../typechain/BasicIssuanceModule"; export { DEXAdapter } from "../../typechain/DEXAdapter"; diff --git a/utils/contracts/setV2.ts b/utils/contracts/setV2.ts index 0e43b615..11272fe4 100644 --- a/utils/contracts/setV2.ts +++ b/utils/contracts/setV2.ts @@ -2,10 +2,12 @@ export { AaveLeverageModule } from "../../typechain/AaveLeverageModule"; export { AaveV2 } from "../../typechain/AaveV2"; export { AirdropModule } from "../../typechain/AirdropModule"; +export { AuctionRebalanceModuleV1 } from "../../typechain/AuctionRebalanceModuleV1"; export { BasicIssuanceModule } from "../../typechain/BasicIssuanceModule"; export { Compound } from "../../typechain/Compound"; export { Controller } from "../../typechain/Controller"; export { ContractCallerMock } from "../../typechain/ContractCallerMock"; +export { ConstantPriceAdapter } from "../../typechain/ConstantPriceAdapter"; export { ComptrollerMock } from "../../typechain/ComptrollerMock"; export { CompoundLeverageModule } from "../../typechain/CompoundLeverageModule"; export { DebtIssuanceModule } from "../../typechain/DebtIssuanceModule"; diff --git a/utils/deploys/deployExtensions.ts b/utils/deploys/deployExtensions.ts index c9b6036f..04b694a1 100644 --- a/utils/deploys/deployExtensions.ts +++ b/utils/deploys/deployExtensions.ts @@ -11,6 +11,7 @@ import { import { AaveLeverageStrategyExtension, AirdropExtension, + AuctionRebalanceExtension, DEXAdapter, ExchangeIssuance, ExchangeIssuanceV2, @@ -34,6 +35,7 @@ import { AaveV3LeverageStrategyExtension__factory, } from "../../typechain"; import { AirdropExtension__factory } from "../../typechain/factories/AirdropExtension__factory"; +import { AuctionRebalanceExtension__factory } from "../../typechain/factories/AuctionRebalanceExtension__factory"; import { DEXAdapter__factory } from "../../typechain/factories/DEXAdapter__factory"; import { ExchangeIssuance__factory } from "../../typechain/factories/ExchangeIssuance__factory"; import { ExchangeIssuanceV2__factory } from "../../typechain/factories/ExchangeIssuanceV2__factory"; @@ -380,6 +382,16 @@ export default class DeployExtensions { return await new AirdropExtension__factory(this._deployerSigner).deploy(manager, airdropModule); } + public async deployAuctionRebalanceExtension( + manager: Address, + auctionModule: Address, + ): Promise { + return await new AuctionRebalanceExtension__factory(this._deployerSigner).deploy( + manager, + auctionModule, + ); + } + public async deployStakeWiseReinvestmentExtension( manager: Address, airdropModule: Address, diff --git a/utils/deploys/deploySetV2.ts b/utils/deploys/deploySetV2.ts index 50f8b424..648ce2e3 100644 --- a/utils/deploys/deploySetV2.ts +++ b/utils/deploys/deploySetV2.ts @@ -6,10 +6,12 @@ import { AaveLeverageModule, AaveV2, AirdropModule, + AuctionRebalanceModuleV1, BasicIssuanceModule, Compound, CompoundLeverageModule, Controller, + ConstantPriceAdapter, ComptrollerMock, ContractCallerMock, DebtIssuanceModule, @@ -35,8 +37,10 @@ import { ether } from "../common"; import { AaveLeverageModule__factory } from "../../typechain/factories/AaveLeverageModule__factory"; import { AaveV2__factory } from "../../typechain/factories/AaveV2__factory"; import { AirdropModule__factory } from "../../typechain/factories/AirdropModule__factory"; +import { AuctionRebalanceModuleV1__factory } from "../../typechain/factories/AuctionRebalanceModuleV1__factory"; import { BasicIssuanceModule__factory } from "../../typechain/factories/BasicIssuanceModule__factory"; import { Controller__factory } from "../../typechain/factories/Controller__factory"; +import { ConstantPriceAdapter__factory } from "../../typechain/factories/ConstantPriceAdapter__factory"; import { Compound__factory } from "../../typechain/factories/Compound__factory"; import { CompoundLeverageModule__factory } from "../../typechain/factories/CompoundLeverageModule__factory"; import { ComptrollerMock__factory } from "../../typechain/factories/ComptrollerMock__factory"; @@ -258,6 +262,10 @@ export default class DeploySetV2 { return await new AirdropModule__factory(this._deployerSigner).deploy(controller); } + public async deployAuctionRebalanceModuleV1(controller: Address): Promise { + return await new AuctionRebalanceModuleV1__factory(this._deployerSigner).deploy(controller); + } + public async deployWrapModule(controller: Address, weth: Address): Promise { return await new WrapModule__factory(this._deployerSigner).deploy(controller, weth); } @@ -275,4 +283,8 @@ export default class DeploySetV2 { this._deployerSigner, ).deploy(); } + + public async deployConstantPriceAdapter(): Promise { + return await new ConstantPriceAdapter__factory(this._deployerSigner).deploy(); + } } diff --git a/utils/fixtures/setFixture.ts b/utils/fixtures/setFixture.ts index e971fe9b..fe7ae177 100644 --- a/utils/fixtures/setFixture.ts +++ b/utils/fixtures/setFixture.ts @@ -4,6 +4,7 @@ import { BigNumber } from "@ethersproject/bignumber"; import { AirdropModule, + AuctionRebalanceModuleV1, BasicIssuanceModule, CompoundLeverageModule, Controller, @@ -44,6 +45,7 @@ export class SetFixture { public factory: SetTokenCreator; public integrationRegistry: IntegrationRegistry; + public auctionModule: AuctionRebalanceModuleV1; public issuanceModule: BasicIssuanceModule; public debtIssuanceModule: DebtIssuanceModule; public streamingFeeModule: StreamingFeeModule; @@ -75,6 +77,7 @@ export class SetFixture { this.integrationRegistry = await this._deployer.setV2.deployIntegrationRegistry(this.controller.address); this.factory = await this._deployer.setV2.deploySetTokenCreator(this.controller.address); + this.auctionModule = await this._deployer.setV2.deployAuctionRebalanceModuleV1(this.controller.address); this.issuanceModule = await this._deployer.setV2.deployBasicIssuanceModule(this.controller.address); this.streamingFeeModule = await this._deployer.setV2.deployStreamingFeeModule(this.controller.address); this.debtIssuanceModule = await this._deployer.setV2.deployDebtIssuanceModule(this.controller.address); @@ -95,6 +98,7 @@ export class SetFixture { ); const modules = [ + this.auctionModule.address, this.issuanceModule.address, this.streamingFeeModule.address, this.debtIssuanceModule.address,