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
Empty file removed .node-xmlhttprequest-sync-8770
Empty file.
118 changes: 117 additions & 1 deletion contracts/core/RebalancingSetToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ 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 { Bytes32 } from "../lib/Bytes32.sol";
import { ICore } from "./interfaces/ICore.sol";
import { ISetFactory } from "./interfaces/ISetFactory.sol";
import { Bytes32 } from "../lib/Bytes32.sol";
import { ISetToken } from "./interfaces/ISetToken.sol";
import { AddressArrayUtils } from "../external/cryptofin/AddressArrayUtils.sol";


/**
Expand All @@ -35,6 +38,7 @@ contract RebalancingSetToken is
{
using SafeMath for uint256;
using Bytes32 for bytes32;
using AddressArrayUtils for address[];

/* ============ Enums ============ */

Expand Down Expand Up @@ -162,6 +166,7 @@ contract RebalancingSetToken is
)
external
{

// Make sure it is manager that is proposing the rebalance
require(msg.sender == manager);

Expand All @@ -178,6 +183,9 @@ contract RebalancingSetToken is
auctionStartPrice = _auctionStartPrice;
auctionPriceDivisor = _auctionPriceDivisor;

// Create token arrays needed for auction
parseUnitArrays();

// Update state parameters
proposalStartTime = block.timestamp;
rebalanceState = State.Proposal;
Expand All @@ -202,6 +210,12 @@ contract RebalancingSetToken is
// Be sure the full proposal period has elapsed
require(block.timestamp >= proposalStartTime.add(proposalPeriod));

// Get core address
address core = ISetFactory(factory).core();

// Redeem current set held by rebalancing token in vault
ICore(core).redeemInVault(currentSet, unitShares.mul(totalSupply_));

// Update state parameters
auctionStartTime = block.timestamp;
rebalanceState = State.Rebalance;
Expand Down Expand Up @@ -331,6 +345,45 @@ contract RebalancingSetToken is
return [unitShares];
}

/*
* Get combinedTokenArray of Rebalancing Set
*
* @return combinedTokenArray
*/
function getCombinedTokenArray()
external
view
returns(address[])
{
return combinedTokenArray;
}

/*
* Get combinedCurrentUnits of Rebalancing Set
*
* @return combinedCurrentUnits
*/
function getCombinedCurrentUnits()
external
view
returns(uint256[])
{
return combinedCurrentUnits;
}

/*
* Get combinedRebalanceUnits of Rebalancing Set
*
* @return combinedRebalanceUnits
*/
function getCombinedRebalanceUnits()
external
view
returns(uint256[])
{
return combinedRebalanceUnits;
}

/* ============ Transfer Overrides ============ */

/*
Expand Down Expand Up @@ -376,4 +429,67 @@ contract RebalancingSetToken is
// Use inherited transferFrom function
return super.transferFrom(_from, _to, _value);
}

/* ============ Internal Functions ============ */
function parseUnitArrays()
internal
{
// Create interfaces for interacting with sets
ISetToken currentSetInterface = ISetToken(currentSet);
ISetToken rebalancingSetInterface = ISetToken(rebalancingSet);

// Create combined token Array
address[] memory oldComponents = currentSetInterface.getComponents();
address[] memory newComponents = rebalancingSetInterface.getComponents();
combinedTokenArray = oldComponents.union(newComponents);

// Get naturalUnit of both sets
uint256 currentSetNaturalUnit = currentSetInterface.naturalUnit();
uint256 rebalancingSetNaturalUnit = rebalancingSetInterface.naturalUnit();

// Get units arrays for both sets
uint256[] memory currentSetUnits = currentSetInterface.getUnits();
uint256[] memory rebalancingSetUnits = rebalancingSetInterface.getUnits();

for (uint256 i=0; i < combinedTokenArray.length; i++) {
// Check if component in arrays and get index if it is
(uint256 indexCurrent, bool isInCurrent) = oldComponents.indexOf(combinedTokenArray[i]);
(uint256 indexRebalance, bool isInRebalance) = newComponents.indexOf(combinedTokenArray[i]);

// Compute and push unit amounts of token in currentSet, push 0 if not in set
if (isInCurrent) {
combinedCurrentUnits.push(
computeUnits(currentSetUnits[indexCurrent], currentSetNaturalUnit)
);
} else {
combinedCurrentUnits.push(uint256(0));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting, do you have to cast this here? uint256(0)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prob not but feel like we've fallen on the standard of explicitly stating what all the uints are

}

// Compute and push unit amounts of token in rebalancingSet, push 0 if not in set
if (isInRebalance) {
combinedRebalanceUnits.push(
computeUnits(rebalancingSetUnits[indexRebalance], rebalancingSetNaturalUnit)
);
} else {
combinedRebalanceUnits.push(uint256(0));
}
}
}

/**
* Function to calculate the transfer value of a component given 1 Set
*
* @param _unit The units of the component token
* @param _naturalUnit The natural unit of the Set token
*/
function computeUnits(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have one of these functions elsewhere? If so, maybe we can avoid duplication by using a lib

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have something similar in Core but don't see a need to have us make a call to it in order to calculate this.

uint256 _unit,
uint256 _naturalUnit
)
internal
returns (uint256)
{
uint256 coefficient = uint256(10) ** uint256(18);
return coefficient.mul(_unit).div(_naturalUnit);
}
}
4 changes: 2 additions & 2 deletions contracts/core/extensions/CoreIssuance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ contract CoreIssuance is
*
* Normally, you should expect to be able to withdraw all of the tokens.
* However, some have central abilities to freeze transfers (e.g. EOS). _toExclude
* allows you to optionally specify which component tokens to exclude when
* allows you to optionally specify which component tokens to exclude when
* redeeming. They will remain in the vault under the users' addresses.
*
* @param _set The address of the Set token
Expand Down Expand Up @@ -365,6 +365,6 @@ contract CoreIssuance is
internal
returns (uint256)
{
return _quantity.div(_naturalUnit).mul(_componentUnits);
return _quantity.mul(_componentUnits).div(_naturalUnit);
}
}
12 changes: 12 additions & 0 deletions contracts/core/interfaces/ICore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ interface ICore {
)
external;

/**
* Function to convert Set Tokens held in vault into underlying components
*
* @param _set The address of the Set token
* @param _quantity The number of tokens to redeem. Should be multiple of natural unit.
*/
function redeemInVault(
address _set,
uint256 _quantity
)
external;

/**
* Deposit multiple tokens to the vault. Quantities should be in the
* order of the addresses of the tokens being deposited.
Expand Down
64 changes: 64 additions & 0 deletions contracts/mocks/core/CoreMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
pragma solidity 0.4.24;

import { Core } from "../../core/Core.sol";
import { ISetToken } from "../../core/interfaces/ISetToken.sol";

// Mock contract implementation of Core with extra functions for testing
contract CoreMock is Core {
constructor(
address _transferProxy,
address _vault
)
public
Core(_transferProxy, _vault)
{}

/*
* Mint set token for given address.
* Can only be called by authorized contracts.
*
* @param _set The address of the Set to mint
* @param _issuer The address of the issuing account
* @param _quantity The number of sets to attribute to issuer
*/
function mint(
address _set,
address _issuer,
uint256 _quantity
)
external
{
ISetToken setToken = ISetToken(_set);

// Issue set token
setToken.mint(
_issuer,
_quantity
);
}

/*
* Burn set token for given address.
* Can only be called by authorized contracts.
*
* @param _set The address of the Set to burn
* @param _from The address of the redeeming account
* @param _quantity The number of sets to burn from redeemer
*/
function burn(
address _set,
address _from,
uint256 _quantity
)
external
{
ISetToken setToken = ISetToken(_set);

// Issue set token
setToken.burn(
_from,
_quantity
);
}
}

Loading