-
Notifications
You must be signed in to change notification settings - Fork 59
[WIP] brian/rebalancing_set_basic #167
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ pragma solidity 0.4.24; | |
import { DetailedERC20 } from "zeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol"; | ||
import { SafeMath } from "zeppelin-solidity/contracts/math/SafeMath.sol"; | ||
import { StandardToken } from "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol"; | ||
import { ISetFactory } from "./interfaces/ISetFactory.sol"; | ||
|
||
/** | ||
* @title SetToken | ||
|
@@ -70,6 +71,24 @@ contract RebalancingToken is | |
uint256 public remainingCurrentSets; | ||
uint256 public rebalanceSetSupply; | ||
|
||
/* ============ Events ============ */ | ||
|
||
event NewManagerAdded( | ||
address newManager, | ||
address oldManager | ||
); | ||
|
||
event RebalanceProposed( | ||
address rebalancingSet, | ||
address indexed auctionLibrary, | ||
uint256 indexed proposalPeriodEndTime | ||
); | ||
|
||
event RebalanceStarted( | ||
address oldSet, | ||
address newSet | ||
); | ||
|
||
|
||
/* ============ Constructor ============ */ | ||
|
||
|
@@ -116,4 +135,240 @@ contract RebalancingToken is | |
lastRebalanceTimestamp = block.timestamp; | ||
rebalanceState = State.Default; | ||
} | ||
|
||
/* ============ Public Functions ============ */ | ||
|
||
/** | ||
* Function used to set the terms of the next rebalance and start the proposal period | ||
* | ||
* | ||
* @param _rebalancingSet The Set to rebalance into | ||
* @param _auctionLibrary The library used to calculate the Dutch Auction price | ||
* @param _curveCoefficient The slope (or convexity) of the price curve | ||
* @param _auctionPriceDivisor The granularity with which the prices change | ||
* @param _auctionStartPrice The price to start the auction at | ||
*/ | ||
function propose( | ||
address _rebalancingSet, | ||
address _auctionLibrary, | ||
uint256 _curveCoefficient, | ||
uint256 _auctionStartPrice, | ||
uint256 _auctionPriceDivisor | ||
) | ||
external | ||
{ | ||
// Make sure it is manager that is proposing the rebalance | ||
require(msg.sender == manager); | ||
|
||
// New proposal cannot be made during a rebalance period | ||
require(rebalanceState == State.Default); | ||
|
||
// Make sure enough time has passed from last rebalance to start a new proposal | ||
require(block.timestamp >= lastRebalanceTimestamp.add(rebalanceInterval)); | ||
|
||
// Set auction parameters | ||
rebalancingSet = _rebalancingSet; | ||
auctionLibrary = _auctionLibrary; | ||
curveCoefficient = _curveCoefficient; | ||
auctionStartPrice = _auctionStartPrice; | ||
auctionPriceDivisor = _auctionPriceDivisor; | ||
|
||
// Update state parameters | ||
proposalStartTime = block.timestamp; | ||
rebalanceState = State.Proposal; | ||
|
||
emit RebalanceProposed( | ||
_rebalancingSet, | ||
_auctionLibrary, | ||
proposalStartTime.add(proposalPeriod) | ||
); | ||
} | ||
|
||
/* | ||
* Initiate rebalance for the rebalancing set. Users can now submit bids. | ||
* | ||
*/ | ||
function rebalance() | ||
external | ||
{ | ||
// Must be in "Proposal" state before going into "Rebalance" state | ||
require(rebalanceState == State.Proposal); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could probably abstract the state transition and timing checks into a private function There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain what you mean? If it's what I think you mean I suppose that would look cleaner but not sure it'd be more efficient. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's just an optimization (can be done later), but we can have a state transition function so we dedupe the logic. |
||
|
||
// Be sure the full proposal period has elapsed | ||
require(block.timestamp >= proposalStartTime.add(proposalPeriod)); | ||
|
||
// Update state parameters | ||
auctionStartTime = block.timestamp; | ||
rebalanceState = State.Rebalance; | ||
|
||
emit RebalanceStarted(currentSet, rebalancingSet); | ||
} | ||
|
||
/* | ||
* Initiate settlement for the rebalancing set. Full functionality now returned to | ||
* set owners. | ||
* | ||
*/ | ||
function settlement() | ||
external | ||
{ | ||
// Must be in Rebalance state to call settlement | ||
require(rebalanceState == State.Rebalance); | ||
|
||
// Set current set to be rebalancing set | ||
currentSet = rebalancingSet; | ||
|
||
// Update state parameters | ||
lastRebalanceTimestamp = block.timestamp; | ||
rebalanceState = State.Default; | ||
} | ||
|
||
/* | ||
* Mint set token for given address. | ||
* Can only be called by authorized contracts. | ||
* | ||
* @param _issuer The address of the issuing account | ||
* @param _quantity The number of sets to attribute to issuer | ||
*/ | ||
function mint( | ||
address _issuer, | ||
uint256 _quantity | ||
) | ||
external | ||
{ | ||
// Check that function caller is Core | ||
require(msg.sender == ISetFactory(factory).core()); | ||
|
||
// Check that set is not in Rebalancing State | ||
require(rebalanceState != State.Rebalance); | ||
|
||
// Update token balance of the issuer | ||
balances[_issuer] = balances[_issuer].add(_quantity); | ||
|
||
// Update the total supply of the set token | ||
totalSupply_ = totalSupply_.add(_quantity); | ||
|
||
// Emit a transfer log with from address being 0 to indicate mint | ||
emit Transfer(address(0), _issuer, _quantity); | ||
} | ||
|
||
/* | ||
* Burn set token for given address. | ||
* Can only be called by authorized contracts. | ||
* | ||
* @param _from The address of the redeeming account | ||
* @param _quantity The number of sets to burn from redeemer | ||
*/ | ||
function burn( | ||
address _from, | ||
uint256 _quantity | ||
) | ||
external | ||
{ | ||
// Check that function caller is Core | ||
require(msg.sender == ISetFactory(factory).core()); | ||
|
||
// Check that set is not in Rebalancing State | ||
require(rebalanceState != State.Rebalance); | ||
|
||
// Require user has tokens to burn | ||
require(balances[_from] >= _quantity); | ||
|
||
// Update token balance of user | ||
balances[_from] = balances[_from].sub(_quantity); | ||
|
||
// Update total supply of Set Token | ||
totalSupply_ = totalSupply_.sub(_quantity); | ||
|
||
// Emit a transfer log with to address being 0 indicating burn | ||
emit Transfer(_from, address(0), _quantity); | ||
} | ||
|
||
/* | ||
* Set new manager address | ||
* | ||
* @param _newManager The address of the redeeming account | ||
*/ | ||
function setManager( | ||
address _newManager | ||
) | ||
external | ||
{ | ||
require(msg.sender == manager); | ||
|
||
emit NewManagerAdded(_newManager, manager); | ||
manager = _newManager; | ||
} | ||
|
||
/* | ||
* Get addresses of setToken underlying the Rebalancing Set | ||
* | ||
* @return componentAddresses Array of currentSet | ||
*/ | ||
function getComponents() | ||
external | ||
view | ||
returns(address[1]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this more efficient? I think the normal getComponents interface is just address[]. Wonder if there's any issues with address[1] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It wouldn't let me return a dynamic address for whatever reason. Perhaps because what's being returned isn't dynamic in nature? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This might be an issue when we go to issue (lol)...I'll have to consider ways to be able to return a dynamic address array |
||
{ | ||
return [currentSet]; | ||
} | ||
|
||
/* | ||
* Get unitShares of Rebalancing Set | ||
* | ||
* @return units Array of component unit | ||
*/ | ||
function getUnits() | ||
external | ||
view | ||
returns(uint256[1]) | ||
{ | ||
return [unitShares]; | ||
} | ||
|
||
/* ============ Transfer Overrides ============ */ | ||
|
||
/* | ||
* ERC20 like transfer function but checks destination is valid | ||
* | ||
* @param _to The address to send Set to | ||
* @param _value The number of Sets to send | ||
* @return bool True on successful transfer | ||
*/ | ||
function transfer( | ||
address _to, | ||
uint256 _value | ||
) | ||
public | ||
returns (bool) | ||
{ | ||
// Confirm address is not this address | ||
require(_to != address(this)); | ||
|
||
// Use inherited transfer function | ||
return super.transfer(_to, _value); | ||
} | ||
|
||
/* | ||
* ERC20 like transferFrom function but checks destination is valid | ||
* | ||
* @param _from The address to send Set from | ||
* @param _to The address to send Set to | ||
* @param _value The number of Sets to send | ||
* @return bool True on successful transfer | ||
*/ | ||
function transferFrom( | ||
address _from, | ||
address _to, | ||
uint256 _value | ||
) | ||
public | ||
returns (bool) | ||
{ | ||
// Confirm address is not this address | ||
require(_to != address(this)); | ||
|
||
// Use inherited transferFrom function | ||
return super.transferFrom(_from, _to, _value); | ||
} | ||
} |
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.
We should have a check to ensure that the address proposed is indeed a Set, perhaps querying Core
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.
Yeah I'd be ok with that.