This repository was archived by the owner on Jan 18, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 58
Master TWAP Auction Branch #625
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,288 @@ | ||
/* | ||
Copyright 2020 Set Labs Inc. | ||
|
||
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. | ||
*/ | ||
|
||
pragma solidity 0.5.7; | ||
pragma experimental "ABIEncoderV2"; | ||
|
||
import { Ownable } from "openzeppelin-solidity/contracts/ownership/Ownable.sol"; | ||
import { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol"; | ||
import { BoundsLibrary } from "set-protocol-contract-utils/contracts/lib/BoundsLibrary.sol"; | ||
|
||
import { Auction } from "./impl/Auction.sol"; | ||
import { ICore } from "../interfaces/ICore.sol"; | ||
import { ILiquidator } from "../interfaces/ILiquidator.sol"; | ||
import { IOracleWhiteList } from "../interfaces/IOracleWhiteList.sol"; | ||
import { ISetToken } from "../interfaces/ISetToken.sol"; | ||
import { LinearAuction } from "./impl/LinearAuction.sol"; | ||
import { Rebalance } from "../lib/Rebalance.sol"; | ||
import { RebalancingLibrary } from "../lib/RebalancingLibrary.sol"; | ||
import { TWAPAuction } from "./twap-impl/TWAPAuction.sol"; | ||
import { TWAPAuctionGetters } from "./twap-impl/TWAPAuctionGetters.sol"; | ||
import { TwoAssetPriceBoundedLinearAuction } from "./impl/TwoAssetPriceBoundedLinearAuction.sol"; | ||
|
||
|
||
/** | ||
* @title TWAPLiquidator | ||
* @author Set Protocol | ||
* | ||
* Contract that holds all the state and functionality required for setting up, returning prices, and tearing | ||
* down TWAP rebalances for RebalancingSetTokens. | ||
*/ | ||
contract TWAPLiquidator is | ||
ILiquidator, | ||
TWAPAuction, | ||
TWAPAuctionGetters, | ||
Ownable | ||
{ | ||
using SafeMath for uint256; | ||
|
||
ICore public core; | ||
string public name; | ||
mapping(address => TWAPAuction.TWAPState) public auctions; | ||
|
||
/* ============ Modifier ============ */ | ||
modifier isValidSet() { | ||
requireValidSet(msg.sender); | ||
_; | ||
} | ||
|
||
/** | ||
* TWAPLiquidator constructor | ||
* | ||
* @param _core Core instance | ||
* @param _oracleWhiteList Oracle WhiteList instance | ||
* @param _auctionPeriod Length of auction in seconds | ||
* @param _rangeStart Percentage above FairValue to begin auction at | ||
* @param _rangeEnd Percentage below FairValue to end auction at | ||
* @param _assetPairHashes List of asset pair unique identifiers | ||
* @param _assetPairBounds List of asset pair USD-denominated chunk auction size bounds | ||
* @param _name Descriptive name of Liquidator | ||
*/ | ||
constructor( | ||
ICore _core, | ||
IOracleWhiteList _oracleWhiteList, | ||
uint256 _auctionPeriod, | ||
uint256 _rangeStart, | ||
uint256 _rangeEnd, | ||
bytes32[] memory _assetPairHashes, | ||
BoundsLibrary.Bounds[] memory _assetPairBounds, | ||
string memory _name | ||
) | ||
public | ||
TWAPAuction( | ||
_oracleWhiteList, | ||
_auctionPeriod, | ||
_rangeStart, | ||
_rangeEnd, | ||
_assetPairHashes, | ||
_assetPairBounds | ||
) | ||
{ | ||
core = _core; | ||
name = _name; | ||
} | ||
|
||
/* ============ External Functions ============ */ | ||
|
||
/** | ||
* Initiates a TWAP auction. Can only be called by a SetToken. | ||
* | ||
* @param _currentSet The Set to rebalance from | ||
* @param _nextSet The Set to rebalance to | ||
* @param _startingCurrentSetQuantity The currentSet quantity to rebalance | ||
* @param _liquidatorData Bytecode formatted data with TWAPLiquidator-specific arguments | ||
*/ | ||
function startRebalance( | ||
ISetToken _currentSet, | ||
ISetToken _nextSet, | ||
uint256 _startingCurrentSetQuantity, | ||
bytes calldata _liquidatorData | ||
) | ||
external | ||
isValidSet | ||
{ | ||
// Validates only 2 components are involved and are supported by oracles | ||
TwoAssetPriceBoundedLinearAuction.validateTwoAssetPriceBoundedAuction( | ||
_currentSet, | ||
_nextSet | ||
); | ||
|
||
// Retrieve the chunk auction size and auction period from liquidator data. | ||
TWAPAuction.TWAPLiquidatorData memory twapLiquidatorData = TWAPAuction.parseLiquidatorData(_liquidatorData); | ||
|
||
// Chunk size must be within bounds and total rebalance length must be below fail auction time | ||
TWAPAuction.validateLiquidatorData( | ||
_currentSet, | ||
_nextSet, | ||
_startingCurrentSetQuantity, | ||
twapLiquidatorData | ||
); | ||
|
||
// Initializes TWAP Auction and commits to TWAP state | ||
TWAPAuction.initializeTWAPAuction( | ||
auctions[msg.sender], | ||
_currentSet, | ||
_nextSet, | ||
_startingCurrentSetQuantity, | ||
twapLiquidatorData | ||
); | ||
} | ||
|
||
/** | ||
* Reduces the remainingCurrentSet quantity and retrieves the current | ||
* bid price for the chunk auction. If this auction completes the chunkAuction, | ||
* the lastChunkAuction parameter is updated. | ||
* Can only be called by a SetToken during an active auction | ||
* | ||
* @param _quantity The currentSetQuantity to rebalance | ||
* @return TokenFlow Struct with array, inflow, and outflow data | ||
*/ | ||
function placeBid( | ||
uint256 _quantity | ||
) | ||
external | ||
isValidSet | ||
returns (Rebalance.TokenFlow memory) | ||
{ | ||
Auction.validateBidQuantity(auction(msg.sender), _quantity); | ||
|
||
Auction.reduceRemainingCurrentSets(auction(msg.sender), _quantity); | ||
|
||
// If the auction is complete, update the chunk auction end time to the present timestamp | ||
if (!hasBiddableQuantity(auction(msg.sender))) { | ||
twapAuction(msg.sender).lastChunkAuctionEnd = block.timestamp; | ||
} | ||
|
||
return getBidPrice(msg.sender, _quantity); | ||
} | ||
|
||
/** | ||
* Retrieves the current chunk auction price for the particular Set | ||
* | ||
* @param _set Address of the SetToken | ||
* @param _quantity The chunk auction's currentSetQuantity to rebalance | ||
* @return TokenFlow Struct with array, inflow, and outflow data | ||
*/ | ||
function getBidPrice( | ||
address _set, | ||
uint256 _quantity | ||
) | ||
public | ||
view | ||
returns (Rebalance.TokenFlow memory) | ||
{ | ||
return LinearAuction.getTokenFlow(chunkAuction(_set), _quantity); | ||
} | ||
|
||
/** | ||
* Initiates the next chunk auction. Callable by anybody. | ||
* | ||
* @param _set Address of the RebalancingSetToken | ||
*/ | ||
function iterateChunkAuction(address _set) external { | ||
validateNextChunkAuction(twapAuction(_set)); | ||
|
||
auctionNextChunk(twapAuction(_set)); | ||
} | ||
|
||
/** | ||
* Validates auction completion and clears auction state. Callable only by a SetToken. | ||
*/ | ||
function settleRebalance() external isValidSet { | ||
require( | ||
!(TWAPAuction.isRebalanceActive(twapAuction(msg.sender))), | ||
"TWAPLiquidator: Rebalance must be complete" | ||
); | ||
|
||
clearAuctionState(msg.sender); | ||
} | ||
|
||
/** | ||
* Clears auction state. | ||
*/ | ||
function endFailedRebalance() external isValidSet { | ||
clearAuctionState(msg.sender); | ||
} | ||
|
||
/** | ||
* Admin function to modify chunk sizes for an asset pair. | ||
* | ||
* @param _assetOne Address of the first asset | ||
* @param _assetTwo Address of the second asset | ||
* @param _assetPairBounds Asset pair USD-denominated chunk auction size bounds | ||
*/ | ||
function setChunkSizeBounds( | ||
address _assetOne, | ||
address _assetTwo, | ||
BoundsLibrary.Bounds memory _assetPairBounds | ||
) | ||
public | ||
onlyOwner | ||
{ | ||
bytes32 pairHash = TWAPAuction.getAssetPairHash(_assetOne, _assetTwo); | ||
|
||
require( | ||
BoundsLibrary.isValid(_assetPairBounds), | ||
"TWAPLiquidator: Bounds invalid" | ||
); | ||
|
||
chunkSizeWhiteList[pairHash] = _assetPairBounds; | ||
} | ||
|
||
/* ============ Getters Functions ============ */ | ||
|
||
function hasRebalanceFailed(address _set) external view returns (bool) { | ||
return LinearAuction.hasAuctionFailed(chunkAuction(_set)); | ||
} | ||
|
||
function auctionPriceParameters(address _set) | ||
external | ||
view | ||
returns (RebalancingLibrary.AuctionPriceParameters memory) | ||
{ | ||
return RebalancingLibrary.AuctionPriceParameters({ | ||
auctionStartTime: auction(_set).startTime, | ||
auctionTimeToPivot: auctionPeriod, | ||
auctionStartPrice: chunkAuction(_set).startPrice, | ||
auctionPivotPrice: chunkAuction(_set).endPrice | ||
}); | ||
} | ||
|
||
/* ============ Private Functions ============ */ | ||
|
||
function clearAuctionState(address _set) private { | ||
delete auctions[_set]; | ||
} | ||
|
||
function twapAuction(address _set) internal view returns(TWAPAuction.TWAPState storage) { | ||
return auctions[_set]; | ||
} | ||
|
||
function chunkAuction(address _set) internal view returns(LinearAuction.State storage) { | ||
return twapAuction(_set).chunkAuction; | ||
} | ||
|
||
function auction(address _set) internal view returns(Auction.Setup storage) { | ||
return chunkAuction(_set).auction; | ||
} | ||
|
||
function requireValidSet(address _set) private view { | ||
require( | ||
core.validSets(_set), | ||
"TWAPLiquidator: Invalid or disabled proposed SetToken address" | ||
); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
Copyright 2020 Set Labs Inc. | ||
|
||
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. | ||
*/ | ||
|
||
pragma solidity 0.5.7; | ||
pragma experimental "ABIEncoderV2"; | ||
|
||
import { Auction } from "./Auction.sol"; | ||
|
||
|
||
/** | ||
* @title AuctionGetters | ||
* @author Set Protocol | ||
* | ||
* Contract containing getters for receiving data from Auction.Setup struct. The auction() getter is implemented in the | ||
* inheriting contract. | ||
*/ | ||
contract AuctionGetters { | ||
|
||
function minimumBid(address _set) external view returns (uint256) { | ||
return auction(_set).minimumBid; | ||
} | ||
|
||
function remainingCurrentSets(address _set) external view returns (uint256) { | ||
return auction(_set).remainingCurrentSets; | ||
} | ||
|
||
function startingCurrentSets(address _set) external view returns (uint256) { | ||
return auction(_set).startingCurrentSets; | ||
} | ||
|
||
function getCombinedTokenArray(address _set) external view returns (address[] memory) { | ||
return auction(_set).combinedTokenArray; | ||
} | ||
|
||
function getCombinedCurrentSetUnits(address _set) external view returns (uint256[] memory) { | ||
return auction(_set).combinedCurrentSetUnits; | ||
} | ||
|
||
function getCombinedNextSetUnits(address _set) external view returns (uint256[] memory) { | ||
return auction(_set).combinedNextSetUnits; | ||
} | ||
|
||
function auction(address _set) internal view returns(Auction.Setup storage); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would have been cool to make these prefixed w/
get
as well. But understand how it wouldn't be backwards compatible