Skip to content
This repository was archived by the owner on Jan 18, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
255 changes: 255 additions & 0 deletions contracts/core/RebalancingSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 ============ */

Expand Down Expand Up @@ -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;
Copy link
Contributor

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

Copy link
Contributor Author

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.

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);
Copy link
Contributor

Choose a reason for hiding this comment

The 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

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Contributor

Choose a reason for hiding this comment

The 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])
Copy link
Contributor

Choose a reason for hiding this comment

The 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]

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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);
}
}
Loading