From 754ccd724a0c91535f92b36c948eae362ad69873 Mon Sep 17 00:00:00 2001 From: felix2feng Date: Mon, 4 Nov 2019 19:38:40 -0800 Subject: [PATCH 1/2] Convert triggers --- contracts/managers/lib/Oscillator.sol | 52 + contracts/managers/triggers/ITrigger.sol | 37 +- .../MovingAverageCrossoverTrigger.sol | 75 + ...ingAverageToAssetPriceCrossoverTrigger.sol | 239 -- .../managers/triggers/RSITrendingTrigger.sol | 142 +- .../movingAverageCrossoverTrigger.spec.ts | 237 ++ ...verageToAssetPriceCrossoverTrigger.spec.ts | 699 ------ .../triggers/rsiTrendingTrigger.spec.ts | 247 +- test/integrations/triggerIndexManager.spec.ts | 2115 ++++++++--------- utils/contract_logs/iTrigger.ts | 19 - utils/contracts.ts | 4 +- utils/helpers/managerHelper.ts | 22 +- 12 files changed, 1456 insertions(+), 2432 deletions(-) create mode 100644 contracts/managers/lib/Oscillator.sol create mode 100644 contracts/managers/triggers/MovingAverageCrossoverTrigger.sol delete mode 100644 contracts/managers/triggers/MovingAverageToAssetPriceCrossoverTrigger.sol create mode 100644 test/contracts/managers/triggers/movingAverageCrossoverTrigger.spec.ts delete mode 100644 test/contracts/managers/triggers/movingAverageToAssetPriceCrossoverTrigger.spec.ts delete mode 100644 utils/contract_logs/iTrigger.ts diff --git a/contracts/managers/lib/Oscillator.sol b/contracts/managers/lib/Oscillator.sol new file mode 100644 index 0000000..0dc6599 --- /dev/null +++ b/contracts/managers/lib/Oscillator.sol @@ -0,0 +1,52 @@ +/* + Copyright 2019 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"; + + +/** + * @title Oscillator + * @author Set Protocol + * + * Library of utility functions to deal with oscillator-related functionality. + */ +library Oscillator { + + enum State { UPPER, LOWER, NEUTRAL } + + // Oscillator bounds typically between 0 and 100 + struct Bounds { + uint256 lower; + uint256 upper; + } + + /* + * Returns upper of value is greater or equal to upper bound. + * Returns lower if lower than lower bound, and neutral if in between. + */ + function getState( + Bounds storage _bounds, + uint256 _value + ) + internal + view + returns(State) + { + return _value >= _bounds.upper ? State.UPPER : + _value < _bounds.lower ? State.LOWER : State.NEUTRAL; + } +} \ No newline at end of file diff --git a/contracts/managers/triggers/ITrigger.sol b/contracts/managers/triggers/ITrigger.sol index cba6951..d35046f 100644 --- a/contracts/managers/triggers/ITrigger.sol +++ b/contracts/managers/triggers/ITrigger.sol @@ -24,48 +24,13 @@ pragma experimental "ABIEncoderV2"; * Interface for interacting with PriceTrigger contracts */ interface ITrigger { - - event TriggerFlipped( - bool _flipTo, - uint256 _triggerFlippedIndex, - uint256 _timestamp - ); - /* * Returns bool indicating whether the current market conditions are bullish. * - * @return The percentage of base asset to be allocated to + * @return Boolean whether condition is bullish */ function isBullish() external view returns (bool); - - /* - * For triggers that require confirmation, start the confirmation period. - */ - function initialTrigger() - external; - - /* - * Confirm the signal. - */ - function confirmTrigger() - external; - - /* - * Check if initialTrigger can be successfully called. - */ - function canInitialTrigger() - external - view - returns (bool); - - /* - * Check if confirmTrigger can be successfully called. - */ - function canConfirmTrigger() - external - view - returns (bool); } \ No newline at end of file diff --git a/contracts/managers/triggers/MovingAverageCrossoverTrigger.sol b/contracts/managers/triggers/MovingAverageCrossoverTrigger.sol new file mode 100644 index 0000000..325bdc6 --- /dev/null +++ b/contracts/managers/triggers/MovingAverageCrossoverTrigger.sol @@ -0,0 +1,75 @@ +/* + Copyright 2019 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 { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol"; + +import { ITrigger } from "./ITrigger.sol"; +import { IOracle } from "../../meta-oracles/interfaces/IOracle.sol"; +import { IMetaOracleV2 } from "../../meta-oracles/interfaces/IMetaOracleV2.sol"; + + +/** + * @title MovingAverageCrossoverTrigger + * @author Set Protocol + * + * Implementing the ITrigger interface, this contract is queried by a + * RebalancingSetToken Manager to determine if the market is in a bullish + * state by checking if the the trading pair price is above or below a moving average. + */ +contract MovingAverageCrossoverTrigger is + ITrigger +{ + using SafeMath for uint256; + + /* ============ State Variables ============ */ + IMetaOracleV2 public movingAveragePriceFeedInstance; + IOracle public assetPairOracleInstance; + uint256 public movingAverageDays; + + /* + * MovingAverageCrossoverTrigger constructor. + * + * @param _movingAveragePriceFeedInstance The address of MA price feed + * @param _assetPairOracleInstance The address of risk asset oracle + * @param _movingAverageDays The amount of days to use in moving average calculation + */ + constructor( + IMetaOracleV2 _movingAveragePriceFeedInstance, + IOracle _assetPairOracleInstance, + uint256 _movingAverageDays + ) + public + { + movingAveragePriceFeedInstance = _movingAveragePriceFeedInstance; + assetPairOracleInstance = _assetPairOracleInstance; + movingAverageDays = _movingAverageDays; + } + + /* ============ External ============ */ + + /* + * If asset pair price greater than moving average return true, else return false + */ + function isBullish() external view returns (bool) { + uint256 movingAverage = movingAveragePriceFeedInstance.read(movingAverageDays); + uint256 assetPairPrice = assetPairOracleInstance.read(); + + return assetPairPrice > movingAverage; + } +} \ No newline at end of file diff --git a/contracts/managers/triggers/MovingAverageToAssetPriceCrossoverTrigger.sol b/contracts/managers/triggers/MovingAverageToAssetPriceCrossoverTrigger.sol deleted file mode 100644 index 1573943..0000000 --- a/contracts/managers/triggers/MovingAverageToAssetPriceCrossoverTrigger.sol +++ /dev/null @@ -1,239 +0,0 @@ -/* - Copyright 2019 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 { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol"; - -import { ITrigger } from "./ITrigger.sol"; -import { IOracle } from "../../meta-oracles/interfaces/IOracle.sol"; -import { IMetaOracleV2 } from "../../meta-oracles/interfaces/IMetaOracleV2.sol"; - - -/** - * @title MovingAverageToAssetPriceCrossoverTrigger - * @author Set Protocol - * - * Implementing the ITrigger interface, this contract is queried by a - * RebalancingSetToken Manager to determine if the market is in a bullish - * state by checking if the the trading pair price is above or below a simple - * or exponential moving average. - * - * Below the moving average means the RebalancingSetToken should be in the - * quote asset, above the moving average the RebalancingSetToken should be - * in the base asset. - */ -contract MovingAverageToAssetPriceCrossoverTrigger is - ITrigger -{ - using SafeMath for uint256; - - /* ============ State Variables ============ */ - IMetaOracleV2 public movingAveragePriceFeedInstance; - IOracle public assetPairOracleInstance; - uint256 public movingAverageDays; - uint256 public triggerFlippedIndex; - bool private lastConfirmedState; - - // Time to start of confirmation period in seconds - uint256 public signalConfirmationMinTime; - // Time to end of confirmation period in seconds - uint256 public signalConfirmationMaxTime; - uint256 public lastInitialTriggerTimestamp; - - bool public requiresConfirmation = true; - - /* - * MovingAverageToAssetPriceCrossoverTrigger constructor. - * - * @param _movingAveragePriceFeedInstance The address of MA price feed - * @param _assetPairOracleInstance The address of risk asset oracle - * @param _movingAverageDays The amount of days to use in moving average calculation - * @param _signalConfirmationMinTime The amount of time, in seconds, until start of confirmation period - * @param _signalConfirmationMaxTime The amount of time, in seconds, until end of confirmation period - * @param _initialState The trigger market state upond deployment - */ - constructor( - IMetaOracleV2 _movingAveragePriceFeedInstance, - IOracle _assetPairOracleInstance, - uint256 _movingAverageDays, - uint256 _signalConfirmationMinTime, - uint256 _signalConfirmationMaxTime, - bool _initialState - - ) - public - { - // Set all state variables - movingAveragePriceFeedInstance = _movingAveragePriceFeedInstance; - assetPairOracleInstance = _assetPairOracleInstance; - movingAverageDays = _movingAverageDays; - signalConfirmationMinTime = _signalConfirmationMinTime; - signalConfirmationMaxTime = _signalConfirmationMaxTime; - lastConfirmedState = _initialState; - triggerFlippedIndex = 0; - } - - /* ============ External ============ */ - - /* - * If enough time has passed since last initial confirmation the current market state is - * calculated then compared to the last confirmed market state. If current state differs - * from last confirmed state then timestamp is logged to be used in calculating the start - * and end of the confirmation period. - */ - function initialTrigger() - external - { - // Make sure enough time has elapsed since last initialTrigger - require( - hasConfirmationWindowElapsed(), - "MovingAverageToAssetPriceCrossoverTrigger.initialTrigger: Not enough time passed from last initial crossover." - ); - - // Get current market state and check that it's different from last confirmed state - bool currentMarketState = getCurrentMarketState(); - require( - currentMarketState != lastConfirmedState, - "MovingAverageToAssetPriceCrossoverTrigger.initialTrigger: Market conditions have not changed since last confirmed state." - ); - - lastInitialTriggerTimestamp = block.timestamp; - } - - /* - * If within the confirmation time period, the current market state is calculated then - * compared to the last confirmed market state. If current state differs from last confirmed - * state then the last confirmed state is updated to the current market state. - */ - function confirmTrigger() - external - { - // Make sure currently in confirmation window - require( - inConfirmationWindow(), - "MovingAverageToAssetPriceCrossoverTrigger.confirmPropose: Confirming signal must be within bounds of the confirm propose." - ); - - // Get current market state and check that it's different from last confirmed state - bool currentMarketState = getCurrentMarketState(); - require( - currentMarketState != lastConfirmedState, - "MovingAverageToAssetPriceCrossoverTrigger.confirmTrigger: Market conditions have not changed since last confirmed state." - ); - - lastConfirmedState = currentMarketState; - triggerFlippedIndex = triggerFlippedIndex.add(1); - - emit TriggerFlipped(currentMarketState, triggerFlippedIndex, block.timestamp); - } - - /* - * Returns if trigger is in bullish state. - * - * @return Whether market conditions are bullish - */ - function isBullish() - external - view - returns (bool) - { - return lastConfirmedState; - } - - /* - * Return if initialTrigger can be called without reverting. - * - * @return Whether in can initialTrigger - */ - function canInitialTrigger() - external - view - returns (bool) - { - if (hasConfirmationWindowElapsed()) { - return getCurrentMarketState() != lastConfirmedState; - } else { - return false; - } - } - - /* - * Return if confirmTrigger can be called without reverting. - * - * @return Whether in can confirmTrigger - */ - function canConfirmTrigger() - external - view - returns (bool) - { - if (inConfirmationWindow()) { - return getCurrentMarketState() != lastConfirmedState; - } else { - return false; - } - } - - /* ============ Internal ============ */ - - /* - * Queries asset and moving average oracle then returns true if asset price exceeds moving - * average otherwise returns false. - * - * @return Whether market conditions are bullish (asset price is over MA) - */ - function getCurrentMarketState() - internal - view - returns(bool) - { - // Query moving average and asset pair oracle - uint256 movingAveragePrice = movingAveragePriceFeedInstance.read(movingAverageDays); - uint256 assetPairPrice = assetPairOracleInstance.read(); - - // If asset pair price greater than moving average return true, else return false - return assetPairPrice > movingAveragePrice; - } - - /* - * Return if enough time passed since last initialTrigger - * - * @return Whether enough time has passed since last initialTrigger - */ - function hasConfirmationWindowElapsed() - internal - view - returns (bool) - { - return block.timestamp > lastInitialTriggerTimestamp.add(signalConfirmationMaxTime); - } - - /* - * Return if currently in confirmation window. - * - * @return Whether in confirmation window - */ - function inConfirmationWindow() - internal - view - returns (bool) - { - return block.timestamp >= lastInitialTriggerTimestamp.add(signalConfirmationMinTime) && - block.timestamp <= lastInitialTriggerTimestamp.add(signalConfirmationMaxTime); - } -} \ No newline at end of file diff --git a/contracts/managers/triggers/RSITrendingTrigger.sol b/contracts/managers/triggers/RSITrendingTrigger.sol index d86db3d..eaa3d06 100644 --- a/contracts/managers/triggers/RSITrendingTrigger.sol +++ b/contracts/managers/triggers/RSITrendingTrigger.sol @@ -22,10 +22,11 @@ import { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol"; import { ITrigger } from "./ITrigger.sol"; import { IOracle } from "../../meta-oracles/interfaces/IOracle.sol"; import { IMetaOracleV2 } from "../../meta-oracles/interfaces/IMetaOracleV2.sol"; +import { Oscillator } from "../lib/Oscillator.sol"; /** - * @title RSITrendingTrigger + * @title RSITrending * @author Set Protocol * * Implementing the ITrigger interface, this contract is queried by a @@ -43,157 +44,58 @@ contract RSITrendingTrigger is using SafeMath for uint256; /* ============ State Variables ============ */ - IMetaOracleV2 public rsiOracleInstance; - // RSI Bound under which strategy indicates bearish market - uint256 public lowerBound; - // RSI Bound over which strategy indicates bullish market - uint256 public upperBound; + IMetaOracleV2 public rsiOracle; + Oscillator.Bounds public bounds; uint256 public rsiTimePeriod; - uint256 public triggerFlippedIndex; - bool private lastConfirmedTrendState; - - bool public requiresConfirmation = false; /* * RSITrendingTrigger constructor. * - * @param _rsiOracleInstance The address of RSI oracle + * @param _rsiOracle The address of RSI oracle * @param _lowerBound Lower bound of RSI to trigger a rebalance * @param _upperBound Upper bound of RSI to trigger a rebalance * @param _rsiTimePeriod The amount of days to use in RSI calculation - * @param _initialTrendState Starting state based on current trend */ constructor( - IMetaOracleV2 _rsiOracleInstance, + IMetaOracleV2 _rsiOracle, uint256 _lowerBound, uint256 _upperBound, - uint256 _rsiTimePeriod, - bool _initialTrendState + uint256 _rsiTimePeriod ) public { - // Check that upper bound value must be greater than lower bound value require( _upperBound >= _lowerBound, - "RSITrendingTrigger.constructor: Upper bound must be greater than lower bound" + "Constructor: Upper bound must be greater than lower bound" ); - // Set all state variables - rsiOracleInstance = _rsiOracleInstance; - lowerBound = _lowerBound; - upperBound = _upperBound; + rsiOracle = _rsiOracle; rsiTimePeriod = _rsiTimePeriod; - lastConfirmedTrendState = _initialTrendState; - triggerFlippedIndex = 0; + bounds = Oscillator.Bounds({ + lower: _lowerBound, + upper: _upperBound + }); } /* ============ External ============ */ - /* - * Since RSI does not require a confirmation leave initialTrigger function unimplemented. - */ - function initialTrigger() - external - {} - /* * If RSI is above upper bound then should be true, if RSI is below lower bound - * then should be false. If in between bounds then returns the state of the current trend. - */ - function confirmTrigger() - external - { - // Query RSI oracle - uint256 rsiValue = rsiOracleInstance.read(rsiTimePeriod); - - // Check RSI trend is different from last confirmed trend state - require( - isNewRSIState(rsiValue), - "RSITrendingTrigger.confirmTrigger: Current RSI value does not change trend state." - ); - - lastConfirmedTrendState = getCurrentMarketState(rsiValue); - triggerFlippedIndex = triggerFlippedIndex.add(1); - - emit TriggerFlipped(lastConfirmedTrendState, triggerFlippedIndex, block.timestamp); - } - - /* - * Returns true if trigger is in bullish state. - * - * @return Whether market conditions are bullish + * then should be false. If in between bounds then revert. */ function isBullish() external view returns (bool) { - return lastConfirmedTrendState; - } - - /* - * Since RSI does not require a confirmation leave canInitialTrigger function unimplemented. - */ - function canInitialTrigger() - external - view - returns (bool) - {} - - /* - * Returns if confirmTrigger could be successfully called without a revert. - * - * @return Whether confirmTrigger can be called - */ - function canConfirmTrigger() - external - view - returns (bool) - { - // Query RSI oracle - uint256 rsiValue = rsiOracleInstance.read(rsiTimePeriod); - - // Check if current RSI value would cause trend state change - return isNewRSIState(rsiValue); - } - - /* ============ External ============ */ - - /* - * Returns if current RSI value would lead to a trend state change - * - * @param _rsiValue Current RSI value - * @return Whether RSI value changes trend state - */ - function isNewRSIState( - uint256 _rsiValue - ) - internal - view - returns (bool) - { - // If RSI value outside bounds evaluate further, else return false - if (_rsiValue >= upperBound || _rsiValue < lowerBound) { - // If market state is different from last confirmed state then return true, else false - return getCurrentMarketState(_rsiValue) != lastConfirmedTrendState; - } else { - return false; - } - } + uint256 rsiValue = rsiOracle.read(rsiTimePeriod); + Oscillator.State rsiState = Oscillator.getState(bounds, rsiValue); + + require( + rsiState != Oscillator.State.NEUTRAL, + "Oscillator: State must not be neutral" + ); - /* - * Returns current market state based on passed RSI value - * - * @param _rsiValue Current RSI value - * @return RSI trend state - */ - function getCurrentMarketState( - uint256 _rsiValue - ) - internal - view - returns (bool) - { - return _rsiValue >= upperBound ? true : false; + return rsiState == Oscillator.State.UPPER; } } \ No newline at end of file diff --git a/test/contracts/managers/triggers/movingAverageCrossoverTrigger.spec.ts b/test/contracts/managers/triggers/movingAverageCrossoverTrigger.spec.ts new file mode 100644 index 0000000..b091045 --- /dev/null +++ b/test/contracts/managers/triggers/movingAverageCrossoverTrigger.spec.ts @@ -0,0 +1,237 @@ +require('module-alias/register'); + +import * as _ from 'lodash'; +import * as ABIDecoder from 'abi-decoder'; +import * as chai from 'chai'; + +import { Address } from 'set-protocol-utils'; +import { BigNumber } from 'bignumber.js'; + +import ChaiSetup from '@utils/chaiSetup'; +import { BigNumberSetup } from '@utils/bigNumberSetup'; +import { Blockchain } from '@utils/blockchain'; +import { ether } from '@utils/units'; + +import { + MedianContract +} from 'set-protocol-contracts'; + +import { + LegacyMakerOracleAdapterContract, + LinearizedPriceDataSourceContract, + MovingAverageOracleV2Contract, + MovingAverageCrossoverTriggerContract, + OracleProxyContract, + TimeSeriesFeedContract, +} from '@utils/contracts'; + +import { + DEFAULT_GAS, + ONE_DAY_IN_SECONDS +} from '@utils/constants'; + +import { getWeb3 } from '@utils/web3Helper'; + +import { ManagerHelper } from '@utils/helpers/managerHelper'; +import { OracleHelper } from '@utils/helpers/oracleHelper'; +import { ProtocolHelper } from '@utils/helpers/protocolHelper'; + +BigNumberSetup.configure(); +ChaiSetup.configure(); + +const MovingAverageCrossoverTrigger = artifacts.require('MovingAverageCrossoverTrigger'); +const web3 = getWeb3(); +const { expect } = chai; +const blockchain = new Blockchain(web3); + +contract('MovingAverageCrossoverTrigger', accounts => { + const [ + deployerAccount, + ] = accounts; + + let ethMedianizer: MedianContract; + let legacyMakerOracleAdapter: LegacyMakerOracleAdapterContract; + let oracleProxy: OracleProxyContract; + let linearizedDataSource: LinearizedPriceDataSourceContract; + let timeSeriesFeed: TimeSeriesFeedContract; + let movingAverageOracle: MovingAverageOracleV2Contract; + + let trigger: MovingAverageCrossoverTriggerContract; + + let initialEthPrice: BigNumber; + + const managerHelper = new ManagerHelper(deployerAccount); + const oracleHelper = new OracleHelper(deployerAccount); + const protocolHelper = new ProtocolHelper(deployerAccount); + + before(async () => { + ABIDecoder.addABI(MovingAverageCrossoverTrigger.abi); + }); + + after(async () => { + ABIDecoder.removeABI(MovingAverageCrossoverTrigger.abi); + }); + + beforeEach(async () => { + blockchain.saveSnapshotAsync(); + + ethMedianizer = await protocolHelper.getDeployedWETHMedianizerAsync(); + await oracleHelper.addPriceFeedOwnerToMedianizer(ethMedianizer, deployerAccount); + + initialEthPrice = ether(150); + await oracleHelper.updateMedianizerPriceAsync( + ethMedianizer, + initialEthPrice, + SetTestUtils.generateTimestamp(1000), + ); + + + legacyMakerOracleAdapter = await oracleHelper.deployLegacyMakerOracleAdapterAsync( + ethMedianizer.address, + ); + + oracleProxy = await oracleHelper.deployOracleProxyAsync( + legacyMakerOracleAdapter.address, + ); + + const interpolationThreshold = ONE_DAY_IN_SECONDS; + linearizedDataSource = await oracleHelper.deployLinearizedPriceDataSourceAsync( + oracleProxy.address, + interpolationThreshold, + ); + + await oracleHelper.addAuthorizedAddressesToOracleProxy( + oracleProxy, + [linearizedDataSource.address] + ); + + const seededValues = _.map(new Array(20), function(el, i) {return ether(150 + i); }); + timeSeriesFeed = await oracleHelper.deployTimeSeriesFeedAsync( + linearizedDataSource.address, + seededValues + ); + + const dataDescription = 'ETH20dayMA'; + movingAverageOracle = await oracleHelper.deployMovingAverageOracleV2Async( + timeSeriesFeed.address, + dataDescription + ); + }); + + afterEach(async () => { + blockchain.revertAsync(); + }); + + describe('#constructor', async () => { + let subjectMovingAveragePriceFeedInstance: Address; + let subjectAssetPairOracleInstance: Address; + let subjectMovingAverageDays: BigNumber; + + beforeEach(async () => { + subjectMovingAveragePriceFeedInstance = movingAverageOracle.address; + subjectAssetPairOracleInstance = oracleProxy.address; + subjectMovingAverageDays = new BigNumber(20); + }); + + async function subject(): Promise { + return managerHelper.deployMovingAverageCrossoverTrigger( + subjectMovingAveragePriceFeedInstance, + subjectAssetPairOracleInstance, + subjectMovingAverageDays, + ); + } + + it('sets the correct moving average oracle address', async () => { + trigger = await subject(); + + const actualMovingAveragePriceFeedAddress = await trigger.movingAveragePriceFeedInstance.callAsync(); + + expect(actualMovingAveragePriceFeedAddress).to.equal(subjectMovingAveragePriceFeedInstance); + }); + + it('sets the correct asset pair oracle address', async () => { + trigger = await subject(); + + const actualAssetPairOracleAddress = await trigger.assetPairOracleInstance.callAsync(); + + expect(actualAssetPairOracleAddress).to.equal(subjectAssetPairOracleInstance); + }); + + it('sets the correct moving average days', async () => { + trigger = await subject(); + + const actualMovingAverageDays = await trigger.movingAverageDays.callAsync(); + + expect(actualMovingAverageDays).to.be.bignumber.equal(subjectMovingAverageDays); + }); + }); + + describe('#isBullish', async () => { + let subjectCaller: Address; + + let updatedValues: BigNumber[]; + let lastPrice: BigNumber; + + before(async () => { + lastPrice = ether(170); + updatedValues = _.map(new Array(19), function(el, i) {return ether(150 + i); }); + }); + + beforeEach(async () => { + const movingAverageDays = new BigNumber(20); + trigger = await managerHelper.deployMovingAverageCrossoverTrigger( + movingAverageOracle.address, + oracleProxy.address, + movingAverageDays, + ); + await oracleHelper.addAuthorizedAddressesToOracleProxy( + oracleProxy, + [trigger.address] + ); + + await oracleHelper.batchUpdateTimeSeriesFeedAsync( + timeSeriesFeed, + ethMedianizer, + updatedValues.length, + updatedValues + ); + + const lastBlockInfo = await web3.eth.getBlock('latest'); + await oracleHelper.updateMedianizerPriceAsync( + ethMedianizer, + lastPrice, + new BigNumber(lastBlockInfo.timestamp + 1), + ); + + subjectCaller = deployerAccount; + }); + + async function subject(): Promise { + return trigger.isBullish.callAsync( + { from: subjectCaller, gas: DEFAULT_GAS} + ); + } + + it('returns true', async () => { + const result = await subject(); + expect(result).to.be.true; + }); + + describe('price going from bullish to bearish', async () => { + before(async () => { + lastPrice = ether(130); + updatedValues = _.map(new Array(19), function(el, i) {return ether(150 - i); }); + }); + + after(async () => { + lastPrice = ether(170); + updatedValues = _.map(new Array(19), function(el, i) {return ether(150 + i); }); + }); + + it('returns false', async () => { + const result = await subject(); + expect(result).to.be.false; + }); + }); + }); +}); \ No newline at end of file diff --git a/test/contracts/managers/triggers/movingAverageToAssetPriceCrossoverTrigger.spec.ts b/test/contracts/managers/triggers/movingAverageToAssetPriceCrossoverTrigger.spec.ts deleted file mode 100644 index 30d31bb..0000000 --- a/test/contracts/managers/triggers/movingAverageToAssetPriceCrossoverTrigger.spec.ts +++ /dev/null @@ -1,699 +0,0 @@ -require('module-alias/register'); - -import * as _ from 'lodash'; -import * as ABIDecoder from 'abi-decoder'; -import * as chai from 'chai'; -import * as setProtocolUtils from 'set-protocol-utils'; - -import { Address } from 'set-protocol-utils'; -import { BigNumber } from 'bignumber.js'; - -import ChaiSetup from '@utils/chaiSetup'; -import { BigNumberSetup } from '@utils/bigNumberSetup'; -import { Blockchain } from '@utils/blockchain'; -import { ether } from '@utils/units'; - -import { - MedianContract -} from 'set-protocol-contracts'; - -import { - LegacyMakerOracleAdapterContract, - LinearizedPriceDataSourceContract, - MovingAverageOracleV2Contract, - MovingAverageToAssetPriceCrossoverTriggerContract, - OracleProxyContract, - TimeSeriesFeedContract, -} from '@utils/contracts'; - -import { - DEFAULT_GAS, - ONE_DAY_IN_SECONDS, - ONE_HOUR_IN_SECONDS, - ZERO -} from '@utils/constants'; - -import { LogTriggerFlipped } from '@utils/contract_logs/iTrigger'; -import { expectRevertError } from '@utils/tokenAssertions'; -import { getWeb3 } from '@utils/web3Helper'; - -import { ManagerHelper } from '@utils/helpers/managerHelper'; -import { OracleHelper } from '@utils/helpers/oracleHelper'; -import { ProtocolHelper } from '@utils/helpers/protocolHelper'; - -BigNumberSetup.configure(); -ChaiSetup.configure(); - -const MovingAverageToAssetPriceCrossoverTrigger = artifacts.require('MovingAverageToAssetPriceCrossoverTrigger'); -const web3 = getWeb3(); -const { expect } = chai; -const blockchain = new Blockchain(web3); -const { SetProtocolTestUtils: SetTestUtils } = setProtocolUtils; -const setTestUtils = new SetTestUtils(web3); - -contract('MovingAverageToAssetPriceCrossoverTrigger', accounts => { - const [ - deployerAccount, - ] = accounts; - - let ethMedianizer: MedianContract; - let legacyMakerOracleAdapter: LegacyMakerOracleAdapterContract; - let oracleProxy: OracleProxyContract; - let linearizedDataSource: LinearizedPriceDataSourceContract; - let timeSeriesFeed: TimeSeriesFeedContract; - let movingAverageOracle: MovingAverageOracleV2Contract; - - let trigger: MovingAverageToAssetPriceCrossoverTriggerContract; - - let initialEthPrice: BigNumber; - - const managerHelper = new ManagerHelper(deployerAccount); - const oracleHelper = new OracleHelper(deployerAccount); - const protocolHelper = new ProtocolHelper(deployerAccount); - - before(async () => { - ABIDecoder.addABI(MovingAverageToAssetPriceCrossoverTrigger.abi); - }); - - after(async () => { - ABIDecoder.removeABI(MovingAverageToAssetPriceCrossoverTrigger.abi); - }); - - beforeEach(async () => { - blockchain.saveSnapshotAsync(); - - ethMedianizer = await protocolHelper.getDeployedWETHMedianizerAsync(); - await oracleHelper.addPriceFeedOwnerToMedianizer(ethMedianizer, deployerAccount); - - initialEthPrice = ether(150); - await oracleHelper.updateMedianizerPriceAsync( - ethMedianizer, - initialEthPrice, - SetTestUtils.generateTimestamp(1000), - ); - - - legacyMakerOracleAdapter = await oracleHelper.deployLegacyMakerOracleAdapterAsync( - ethMedianizer.address, - ); - - oracleProxy = await oracleHelper.deployOracleProxyAsync( - legacyMakerOracleAdapter.address, - ); - - const interpolationThreshold = ONE_DAY_IN_SECONDS; - linearizedDataSource = await oracleHelper.deployLinearizedPriceDataSourceAsync( - oracleProxy.address, - interpolationThreshold, - ); - - await oracleHelper.addAuthorizedAddressesToOracleProxy( - oracleProxy, - [linearizedDataSource.address] - ); - - const seededValues = _.map(new Array(20), function(el, i) {return ether(150 + i); }); - timeSeriesFeed = await oracleHelper.deployTimeSeriesFeedAsync( - linearizedDataSource.address, - seededValues - ); - - const dataDescription = 'ETH20dayMA'; - movingAverageOracle = await oracleHelper.deployMovingAverageOracleV2Async( - timeSeriesFeed.address, - dataDescription - ); - }); - - afterEach(async () => { - blockchain.revertAsync(); - }); - - describe('#constructor', async () => { - let subjectMovingAveragePriceFeedInstance: Address; - let subjectAssetPairOracleInstance: Address; - let subjectMovingAverageDays: BigNumber; - let subjectInitialState: boolean; - let subjectSignalConfirmationMinTime: BigNumber; - let subjectSignalConfirmationMaxTime: BigNumber; - - beforeEach(async () => { - subjectMovingAveragePriceFeedInstance = movingAverageOracle.address; - subjectAssetPairOracleInstance = oracleProxy.address; - subjectMovingAverageDays = new BigNumber(20); - subjectInitialState = false; - subjectSignalConfirmationMinTime = ONE_HOUR_IN_SECONDS.mul(6); - subjectSignalConfirmationMaxTime = ONE_HOUR_IN_SECONDS.mul(12); - }); - - async function subject(): Promise { - return managerHelper.deployMovingAverageToAssetPriceCrossoverTrigger( - subjectMovingAveragePriceFeedInstance, - subjectAssetPairOracleInstance, - subjectMovingAverageDays, - subjectInitialState, - subjectSignalConfirmationMinTime, - subjectSignalConfirmationMaxTime - ); - } - - it('sets the correct moving average oracle address', async () => { - trigger = await subject(); - - const actualMovingAveragePriceFeedAddress = await trigger.movingAveragePriceFeedInstance.callAsync(); - - expect(actualMovingAveragePriceFeedAddress).to.equal(subjectMovingAveragePriceFeedInstance); - }); - - it('sets the correct asset pair oracle address', async () => { - trigger = await subject(); - - const actualAssetPairOracleAddress = await trigger.assetPairOracleInstance.callAsync(); - - expect(actualAssetPairOracleAddress).to.equal(subjectAssetPairOracleInstance); - }); - - it('sets the correct moving average days', async () => { - trigger = await subject(); - - const actualMovingAverageDays = await trigger.movingAverageDays.callAsync(); - - expect(actualMovingAverageDays).to.be.bignumber.equal(subjectMovingAverageDays); - }); - - it('sets the correct signalConfirmationMinTime', async () => { - trigger = await subject(); - - const actualSignalConfirmationMinTime = await trigger.signalConfirmationMinTime.callAsync(); - - expect(actualSignalConfirmationMinTime).to.be.bignumber.equal(subjectSignalConfirmationMinTime); - }); - - it('sets the correct signalConfirmationMaxTime', async () => { - trigger = await subject(); - - const actualSignalConfirmationMaxTime = await trigger.signalConfirmationMaxTime.callAsync(); - - expect(actualSignalConfirmationMaxTime).to.be.bignumber.equal(subjectSignalConfirmationMaxTime); - }); - - it('sets the correct lastConfirmedState', async () => { - trigger = await subject(); - - const actualBaseAssetAllocation = await trigger.isBullish.callAsync(); - - expect(actualBaseAssetAllocation).to.be.false; - }); - - it('sets the current triggerFlippedIndex to 0', async () => { - trigger = await subject(); - - const actualTriggerFlippedIndex = await trigger.triggerFlippedIndex.callAsync(); - - expect(actualTriggerFlippedIndex).to.be.bignumber.equal(ZERO); - }); - - it('deployed with requiresConfirmation set to true', async () => { - trigger = await subject(); - - const requiresConfirmation = await trigger.requiresConfirmation.callAsync(); - - expect(requiresConfirmation).to.be.true; - }); - }); - - describe('#initialTrigger', async () => { - let subjectCaller: Address; - - let updatedValues: BigNumber[]; - - before(async () => { - updatedValues = _.map(new Array(19), function(el, i) {return ether(150 + i); }); - }); - - beforeEach(async () => { - const movingAverageDays = new BigNumber(20); - const initialState = false; - const signalConfirmationMinTime = ONE_HOUR_IN_SECONDS.mul(6); - const signalConfirmationMaxTime = ONE_HOUR_IN_SECONDS.mul(12); - trigger = await managerHelper.deployMovingAverageToAssetPriceCrossoverTrigger( - movingAverageOracle.address, - oracleProxy.address, - movingAverageDays, - initialState, - signalConfirmationMinTime, - signalConfirmationMaxTime - ); - await oracleHelper.addAuthorizedAddressesToOracleProxy( - oracleProxy, - [trigger.address] - ); - - await oracleHelper.batchUpdateTimeSeriesFeedAsync( - timeSeriesFeed, - ethMedianizer, - updatedValues.length, - updatedValues - ); - - subjectCaller = deployerAccount; - }); - - async function subject(): Promise { - return trigger.initialTrigger.sendTransactionAsync( - { from: subjectCaller, gas: DEFAULT_GAS} - ); - } - - it('sets the proposalTimestamp correctly', async () => { - await subject(); - - const block = await web3.eth.getBlock('latest'); - const expectedTimestamp = new BigNumber(block.timestamp); - - const actualTimestamp = await trigger.lastInitialTriggerTimestamp.callAsync(); - expect(actualTimestamp).to.be.bignumber.equal(expectedTimestamp); - }); - - describe('but not enough time has passed from last initial propose', async () => { - beforeEach(async () => { - await trigger.initialTrigger.sendTransactionAsync(); - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - - describe('but price trigger has not flipped', async () => { - before(async () => { - updatedValues = _.map(new Array(19), function(el, i) {return ether(170 - i); }); - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - }); - - describe('#confirmTrigger', async () => { - let subjectTimeFastForward: BigNumber; - let subjectCaller: Address; - - let updatedValues: BigNumber[]; - let lastPrice: BigNumber; - let initialState: boolean; - let signalConfirmationMinTime: BigNumber; - let signalConfirmationMaxTime: BigNumber; - - before(async () => { - initialState = false; - lastPrice = ether(170); - updatedValues = _.map(new Array(19), function(el, i) {return ether(150 + i); }); - }); - - beforeEach(async () => { - const movingAverageDays = new BigNumber(20); - signalConfirmationMinTime = ONE_HOUR_IN_SECONDS.mul(6); - signalConfirmationMaxTime = ONE_HOUR_IN_SECONDS.mul(12); - trigger = await managerHelper.deployMovingAverageToAssetPriceCrossoverTrigger( - movingAverageOracle.address, - oracleProxy.address, - movingAverageDays, - initialState, - signalConfirmationMinTime, - signalConfirmationMaxTime - ); - await oracleHelper.addAuthorizedAddressesToOracleProxy( - oracleProxy, - [trigger.address] - ); - - await oracleHelper.batchUpdateTimeSeriesFeedAsync( - timeSeriesFeed, - ethMedianizer, - updatedValues.length, - updatedValues - ); - - await trigger.initialTrigger.sendTransactionAsync(); - - const lastBlockInfo = await web3.eth.getBlock('latest'); - await oracleHelper.updateMedianizerPriceAsync( - ethMedianizer, - lastPrice, - new BigNumber(lastBlockInfo.timestamp + 1), - ); - - subjectTimeFastForward = signalConfirmationMinTime.add(1); - subjectCaller = deployerAccount; - }); - - async function subject(): Promise { - await blockchain.increaseTimeAsync(subjectTimeFastForward); - return trigger.confirmTrigger.sendTransactionAsync( - { from: subjectCaller, gas: DEFAULT_GAS} - ); - } - - it('sets the lastConfirmedAllocation correctly', async () => { - await subject(); - - const actualLastConfirmedAllocation = await trigger.isBullish.callAsync(); - expect(actualLastConfirmedAllocation).to.be.true; - }); - - it('sets the current triggerFlippedIndex to 1', async () => { - await subject(); - - const actualTriggerFlippedIndex = await trigger.triggerFlippedIndex.callAsync(); - - expect(actualTriggerFlippedIndex).to.be.bignumber.equal(new BigNumber(1)); - }); - - it('emits the correct TriggerFlipped event', async () => { - const txHash = await subject(); - - const block = await web3.eth.getBlock('latest'); - const expectedTimestamp = new BigNumber(block.timestamp); - - const formattedLogs = await setTestUtils.getLogsFromTxHash(txHash); - const expectedLogs = LogTriggerFlipped( - true, - new BigNumber(1), - expectedTimestamp, - trigger.address - ); - - await SetTestUtils.assertLogEquivalence(formattedLogs, expectedLogs); - }); - - describe('but price trigger has not flipped', async () => { - before(async () => { - lastPrice = ether(150); - }); - - after(async () => { - lastPrice = ether(170); - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - - describe('price going from bullish to bearish', async () => { - before(async () => { - initialState = true; - lastPrice = ether(130); - updatedValues = _.map(new Array(19), function(el, i) {return ether(150 - i); }); - }); - - after(async () => { - initialState = false; - lastPrice = ether(170); - updatedValues = _.map(new Array(19), function(el, i) {return ether(150 + i); }); - }); - - it('sets the lastConfirmedAllocation correctly', async () => { - await subject(); - - const actualLastConfirmedAllocation = await trigger.isBullish.callAsync(); - expect(actualLastConfirmedAllocation).to.be.false; - }); - - describe('but price trigger has not flipped', async () => { - before(async () => { - lastPrice = ether(150); - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - }); - - describe('but not enough time has passed from initial propose', async () => { - beforeEach(async () => { - subjectTimeFastForward = signalConfirmationMinTime.sub(10); - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - - describe('but too much time has passed from initial propose', async () => { - beforeEach(async () => { - subjectTimeFastForward = signalConfirmationMaxTime.add(1); - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - }); - - describe('#canInitialTrigger', async () => { - let subjectCaller: Address; - - let updatedValues: BigNumber[]; - - before(async () => { - updatedValues = _.map(new Array(19), function(el, i) {return ether(150 + i); }); - }); - - beforeEach(async () => { - const movingAverageDays = new BigNumber(20); - const initialState = false; - const signalConfirmationMinTime = ONE_HOUR_IN_SECONDS.mul(6); - const signalConfirmationMaxTime = ONE_HOUR_IN_SECONDS.mul(12); - trigger = await managerHelper.deployMovingAverageToAssetPriceCrossoverTrigger( - movingAverageOracle.address, - oracleProxy.address, - movingAverageDays, - initialState, - signalConfirmationMinTime, - signalConfirmationMaxTime - ); - await oracleHelper.addAuthorizedAddressesToOracleProxy( - oracleProxy, - [trigger.address] - ); - - await oracleHelper.batchUpdateTimeSeriesFeedAsync( - timeSeriesFeed, - ethMedianizer, - updatedValues.length, - updatedValues - ); - - subjectCaller = deployerAccount; - }); - - async function subject(): Promise { - return trigger.canInitialTrigger.callAsync( - { from: subjectCaller, gas: DEFAULT_GAS} - ); - } - - it('returns true', async () => { - const canInitialTrigger = await subject(); - - expect(canInitialTrigger).to.be.true; - }); - - describe('but not enough time has passed from last initial propose', async () => { - beforeEach(async () => { - await trigger.initialTrigger.sendTransactionAsync(); - }); - - it('should return false', async () => { - const canInitialTrigger = await subject(); - - expect(canInitialTrigger).to.be.false; - }); - }); - - describe('but price trigger has not flipped', async () => { - before(async () => { - updatedValues = _.map(new Array(19), function(el, i) {return ether(170 - i); }); - }); - - it('should return false', async () => { - const canInitialTrigger = await subject(); - - expect(canInitialTrigger).to.be.false; - }); - }); - }); - - describe('#canConfirmTrigger', async () => { - let subjectTimeFastForward: BigNumber; - let subjectCaller: Address; - - let updatedValues: BigNumber[]; - let lastPrice: BigNumber; - let initialState: boolean; - let signalConfirmationMinTime: BigNumber; - let signalConfirmationMaxTime: BigNumber; - - before(async () => { - initialState = false; - lastPrice = ether(170); - updatedValues = _.map(new Array(19), function(el, i) {return ether(150 + i); }); - }); - - beforeEach(async () => { - const movingAverageDays = new BigNumber(20); - signalConfirmationMinTime = ONE_HOUR_IN_SECONDS.mul(6); - signalConfirmationMaxTime = ONE_HOUR_IN_SECONDS.mul(12); - trigger = await managerHelper.deployMovingAverageToAssetPriceCrossoverTrigger( - movingAverageOracle.address, - oracleProxy.address, - movingAverageDays, - initialState, - signalConfirmationMinTime, - signalConfirmationMaxTime - ); - await oracleHelper.addAuthorizedAddressesToOracleProxy( - oracleProxy, - [trigger.address] - ); - - await oracleHelper.batchUpdateTimeSeriesFeedAsync( - timeSeriesFeed, - ethMedianizer, - updatedValues.length, - updatedValues - ); - - await trigger.initialTrigger.sendTransactionAsync(); - - const lastBlockInfo = await web3.eth.getBlock('latest'); - await oracleHelper.updateMedianizerPriceAsync( - ethMedianizer, - lastPrice, - new BigNumber(lastBlockInfo.timestamp + 1), - ); - - subjectTimeFastForward = signalConfirmationMinTime.add(1); - subjectCaller = deployerAccount; - }); - - async function subject(): Promise { - await blockchain.increaseTimeAsync(subjectTimeFastForward); - return trigger.canConfirmTrigger.callAsync( - { from: subjectCaller, gas: DEFAULT_GAS} - ); - } - - it('returns true', async () => { - const canInitialTrigger = await subject(); - - expect(canInitialTrigger).to.be.true; - }); - - describe('but price trigger has not flipped', async () => { - before(async () => { - lastPrice = ether(150); - }); - - after(async () => { - lastPrice = ether(170); - }); - - it('should return false', async () => { - const canInitialTrigger = await subject(); - - expect(canInitialTrigger).to.be.false; - }); - }); - - describe('price going from bullish to bearish', async () => { - before(async () => { - initialState = true; - lastPrice = ether(130); - updatedValues = _.map(new Array(19), function(el, i) {return ether(150 - i); }); - }); - - after(async () => { - initialState = false; - lastPrice = ether(170); - updatedValues = _.map(new Array(19), function(el, i) {return ether(150 + i); }); - }); - - it('should return true', async () => { - const canInitialTrigger = await subject(); - - expect(canInitialTrigger).to.be.true; - }); - - describe('but price trigger has not flipped', async () => { - before(async () => { - lastPrice = ether(150); - }); - - it('should return false', async () => { - const canInitialTrigger = await subject(); - - expect(canInitialTrigger).to.be.false; - }); - }); - }); - - describe('but not enough time has passed from initial propose', async () => { - beforeEach(async () => { - subjectTimeFastForward = signalConfirmationMinTime.sub(10); - }); - - it('should return false', async () => { - const canInitialTrigger = await subject(); - - expect(canInitialTrigger).to.be.false; - }); - }); - - describe('but too much time has passed from initial propose', async () => { - beforeEach(async () => { - subjectTimeFastForward = signalConfirmationMaxTime.add(1); - }); - - it('should return false', async () => { - const canInitialTrigger = await subject(); - - expect(canInitialTrigger).to.be.false; - }); - }); - }); - - describe('#isBullish', async () => { - let initialState: boolean; - - beforeEach(async () => { - const movingAverageDays = new BigNumber(20); - initialState = false; - const signalConfirmationMinTime = ONE_HOUR_IN_SECONDS.mul(6); - const signalConfirmationMaxTime = ONE_HOUR_IN_SECONDS.mul(12); - trigger = await managerHelper.deployMovingAverageToAssetPriceCrossoverTrigger( - movingAverageOracle.address, - oracleProxy.address, - movingAverageDays, - initialState, - signalConfirmationMinTime, - signalConfirmationMaxTime - ); - }); - - async function subject(): Promise { - return trigger.isBullish.callAsync(); - } - - it('retrieves the lastConfirmedState', async () => { - const actualLastConfirmedState = await subject(); - - const expectedLastConfirmedState = initialState; - expect(actualLastConfirmedState).to.be.equal(expectedLastConfirmedState); - }); - }); -}); \ No newline at end of file diff --git a/test/contracts/managers/triggers/rsiTrendingTrigger.spec.ts b/test/contracts/managers/triggers/rsiTrendingTrigger.spec.ts index e86ab2d..36035cf 100644 --- a/test/contracts/managers/triggers/rsiTrendingTrigger.spec.ts +++ b/test/contracts/managers/triggers/rsiTrendingTrigger.spec.ts @@ -3,7 +3,6 @@ require('module-alias/register'); import * as _ from 'lodash'; import * as ABIDecoder from 'abi-decoder'; import * as chai from 'chai'; -import * as setProtocolUtils from 'set-protocol-utils'; import { Address } from 'set-protocol-utils'; import { BigNumber } from 'bignumber.js'; @@ -28,11 +27,9 @@ import { import { DEFAULT_GAS, - ONE_DAY_IN_SECONDS, - ZERO + ONE_DAY_IN_SECONDS } from '@utils/constants'; -import { LogTriggerFlipped } from '@utils/contract_logs/iTrigger'; import { expectRevertError } from '@utils/tokenAssertions'; import { getWeb3 } from '@utils/web3Helper'; @@ -47,8 +44,6 @@ const RSITrendingTrigger = artifacts.require('RSITrendingTrigger'); const web3 = getWeb3(); const { expect } = chai; const blockchain = new Blockchain(web3); -const { SetProtocolTestUtils: SetTestUtils } = setProtocolUtils; -const setTestUtils = new SetTestUtils(web3); contract('RSITrendingTrigger', accounts => { const [ @@ -134,14 +129,12 @@ contract('RSITrendingTrigger', accounts => { let subjectLowerBound: BigNumber; let subjectUpperBound: BigNumber; let subjectRSITimePeriod: BigNumber; - let subjectInitialTrendState: boolean; beforeEach(async () => { subjectLowerBound = new BigNumber(40); subjectUpperBound = new BigNumber(60); subjectRSIOracleInstance = rsiOracle.address; subjectRSITimePeriod = new BigNumber(14); - subjectInitialTrendState = false; }); async function subject(): Promise { @@ -150,14 +143,13 @@ contract('RSITrendingTrigger', accounts => { subjectLowerBound, subjectUpperBound, subjectRSITimePeriod, - subjectInitialTrendState ); } it('sets the correct RSI oracle address', async () => { trigger = await subject(); - const actualRSIOracleAddress = await trigger.rsiOracleInstance.callAsync(); + const actualRSIOracleAddress = await trigger.rsiOracle.callAsync(); expect(actualRSIOracleAddress).to.equal(subjectRSIOracleInstance); }); @@ -165,7 +157,7 @@ contract('RSITrendingTrigger', accounts => { it('sets the correct lower bound', async () => { trigger = await subject(); - const actualRSILowerBound = await trigger.lowerBound.callAsync(); + const [actualRSILowerBound] = await trigger.bounds.callAsync(); expect(actualRSILowerBound).to.be.bignumber.equal(subjectLowerBound); }); @@ -173,7 +165,7 @@ contract('RSITrendingTrigger', accounts => { it('sets the correct upper bound', async () => { trigger = await subject(); - const actualRSIUpperBound = await trigger.upperBound.callAsync(); + const [, actualRSIUpperBound] = await trigger.bounds.callAsync(); expect(actualRSIUpperBound).to.be.bignumber.equal(subjectUpperBound); }); @@ -186,44 +178,6 @@ contract('RSITrendingTrigger', accounts => { expect(actualRSITimePeriod).to.be.bignumber.equal(subjectRSITimePeriod); }); - it('sets the current trend state to false', async () => { - trigger = await subject(); - - const actualCurrentTrendAllocation = await trigger.isBullish.callAsync(); - - expect(actualCurrentTrendAllocation).to.be.false; - }); - - it('sets the current triggerFlippedIndex to 0', async () => { - trigger = await subject(); - - const actualTriggerFlippedIndex = await trigger.triggerFlippedIndex.callAsync(); - - expect(actualTriggerFlippedIndex).to.be.bignumber.equal(ZERO); - }); - - it('deployed with requiresConfirmation set to false', async () => { - trigger = await subject(); - - const requiresConfirmation = await trigger.requiresConfirmation.callAsync(); - - expect(requiresConfirmation).to.be.false; - }); - - describe('when initial trend allocation is 100', async () => { - beforeEach(async () => { - subjectInitialTrendState = true; - }); - - it('sets the current trend allocation to 100', async () => { - trigger = await subject(); - - const actualCurrentTrendAllocation = await trigger.isBullish.callAsync(); - - expect(actualCurrentTrendAllocation).to.be.true; - }); - }); - describe('when lower bound is higher than upper bound', async () => { beforeEach(async () => { subjectLowerBound = new BigNumber(60); @@ -236,16 +190,14 @@ contract('RSITrendingTrigger', accounts => { }); }); - describe('#confirmTrigger', async () => { + describe('#isBullish', async () => { let subjectCaller: Address; - let initialTrendState: boolean; let updatedValues: BigNumber[]; before(async () => { // Prices are increasing each day updatedValues = _.map(new Array(15), function(el, i) {return ether(150 + i); }); - initialTrendState = false; }); beforeEach(async () => { @@ -258,7 +210,6 @@ contract('RSITrendingTrigger', accounts => { lowerBound, upperBound, rsiTimePeriod, - initialTrendState, ); await oracleHelper.addAuthorizedAddressesToOracleProxy( oracleProxy, @@ -274,58 +225,26 @@ contract('RSITrendingTrigger', accounts => { subjectCaller = deployerAccount; }); - async function subject(): Promise { - return trigger.confirmTrigger.sendTransactionAsync( + async function subject(): Promise { + return trigger.isBullish.callAsync( { from: subjectCaller, gas: DEFAULT_GAS} ); } it('when RSI over 60 it returns true', async () => { - await subject(); - - const actualReturnedTrendState = await trigger.isBullish.callAsync(); - - expect(actualReturnedTrendState).to.be.true; - }); - - it('sets the current triggerFlippedIndex to 1', async () => { - await subject(); - - const actualTriggerFlippedIndex = await trigger.triggerFlippedIndex.callAsync(); - - expect(actualTriggerFlippedIndex).to.be.bignumber.equal(new BigNumber(1)); - }); - - it('emits the correct TriggerFlipped event', async () => { - const txHash = await subject(); - - const block = await web3.eth.getBlock('latest'); - const expectedTimestamp = new BigNumber(block.timestamp); - - const formattedLogs = await setTestUtils.getLogsFromTxHash(txHash); - const expectedLogs = LogTriggerFlipped( - true, - new BigNumber(1), - expectedTimestamp, - trigger.address - ); - - await SetTestUtils.assertLogEquivalence(formattedLogs, expectedLogs); + const result = await subject(); + expect(result).to.be.true; }); describe('when RSI is below 40', async () => { before(async () => { // Prices are decreasing each day updatedValues = _.map(new Array(15), function(el, i) {return ether(170 - i); }); - initialTrendState = true; }); it('returns false', async () => { - await subject(); - - const actualReturnedTrendState = await trigger.isBullish.callAsync(); - - expect(actualReturnedTrendState).to.be.false; + const result = await subject(); + expect(result).to.be.false; }); }); @@ -355,150 +274,6 @@ contract('RSITrendingTrigger', accounts => { await expectRevertError(subject()); }); }); - - describe('when RSI trigger state does not change', async () => { - before(async () => { - initialTrendState = true; - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - }); - - describe('#canConfirmTrigger', async () => { - let subjectCaller: Address; - - let initialTrendState: boolean; - let updatedValues: BigNumber[]; - - before(async () => { - // Prices are increasing each day - updatedValues = _.map(new Array(15), function(el, i) {return ether(150 + i); }); - initialTrendState = false; - }); - - beforeEach(async () => { - const rsiTimePeriod = new BigNumber(14); - const lowerBound = new BigNumber(40); - const upperBound = new BigNumber(60); - - trigger = await managerHelper.deployRSITrendingTrigger( - rsiOracle.address, - lowerBound, - upperBound, - rsiTimePeriod, - initialTrendState, - ); - await oracleHelper.addAuthorizedAddressesToOracleProxy( - oracleProxy, - [trigger.address] - ); - await oracleHelper.batchUpdateTimeSeriesFeedAsync( - timeSeriesFeed, - ethMedianizer, - updatedValues.length, - updatedValues - ); - - subjectCaller = deployerAccount; - }); - - async function subject(): Promise { - return trigger.canConfirmTrigger.callAsync( - { from: subjectCaller, gas: DEFAULT_GAS} - ); - } - - it('when RSI over 60 it returns true', async () => { - const canConfirm = await subject(); - - expect(canConfirm).to.be.true; - }); - - describe('when RSI is below 40', async () => { - before(async () => { - // Prices are decreasing each day - updatedValues = _.map(new Array(15), function(el, i) {return ether(170 - i); }); - initialTrendState = true; - }); - - it('returns true', async () => { - const canConfirm = await subject(); - - expect(canConfirm).to.be.true; - }); - }); - - describe('when RSI is between 40 and 60', async () => { - before(async () => { - // Prices are alternating each day - updatedValues = [ - ether(170), - ether(150), - ether(170), - ether(150), - ether(170), - ether(150), - ether(170), - ether(150), - ether(170), - ether(150), - ether(170), - ether(150), - ether(170), - ether(150), - ether(170), - ]; - }); - - it('should return false', async () => { - const canConfirm = await subject(); - - expect(canConfirm).to.be.false; - }); - }); - - describe('when RSI trigger state does not change', async () => { - before(async () => { - initialTrendState = true; - }); - - it('should return false', async () => { - const canConfirm = await subject(); - - expect(canConfirm).to.be.false; - }); - }); }); - describe('#isBullish', async () => { - let initialState: boolean; - - beforeEach(async () => { - initialState = false; - const rsiTimePeriod = new BigNumber(14); - const lowerBound = new BigNumber(40); - const upperBound = new BigNumber(60); - trigger = await managerHelper.deployRSITrendingTrigger( - rsiOracle.address, - lowerBound, - upperBound, - rsiTimePeriod, - initialState, - ); - }); - - async function subject(): Promise { - return trigger.isBullish.callAsync(); - } - - it('retrieves the lastConfirmedTrend', async () => { - const actualLastConfirmedTrend = await subject(); - - const expectedLastConfirmedTrend = initialState; - expect(actualLastConfirmedTrend).to.be.equal(expectedLastConfirmedTrend); - }); - }); }); \ No newline at end of file diff --git a/test/integrations/triggerIndexManager.spec.ts b/test/integrations/triggerIndexManager.spec.ts index d460a19..a6ce73f 100644 --- a/test/integrations/triggerIndexManager.spec.ts +++ b/test/integrations/triggerIndexManager.spec.ts @@ -1,1065 +1,1050 @@ -require('module-alias/register'); - -import * as _ from 'lodash'; -import * as ABIDecoder from 'abi-decoder'; -import * as chai from 'chai'; -import * as setProtocolUtils from 'set-protocol-utils'; - -import { Address } from 'set-protocol-utils'; -import { BigNumber } from 'bignumber.js'; - -import ChaiSetup from '@utils/chaiSetup'; -import { BigNumberSetup } from '@utils/bigNumberSetup'; -import { Blockchain } from '@utils/blockchain'; -import { ether } from '@utils/units'; -import { - Core, - CoreContract, - LinearAuctionPriceCurveContract, - MedianContract, - RebalancingSetTokenContract, - RebalancingSetTokenFactoryContract, - SetTokenContract, - SetTokenFactoryContract, - TransferProxyContract, - WethMockContract, - WhiteListContract, -} from 'set-protocol-contracts'; -import { - BinaryAllocatorContract, - ConstantPriceOracleContract, - EMAOracleContract, - LegacyMakerOracleAdapterContract, - LinearizedEMATimeSeriesFeedContract, - MovingAverageToAssetPriceCrossoverTriggerContract, - OracleProxyContract, - TriggerIndexManagerContract, - USDCMockContract, -} from '@utils/contracts'; - -import { - DEFAULT_GAS, - ETH_DECIMALS, - ONE, - ONE_DAY_IN_SECONDS, - ONE_HOUR_IN_SECONDS, - RISK_COLLATERAL_NATURAL_UNIT, - STABLE_COLLATERAL_NATURAL_UNIT, - USDC_DECIMALS, - ZERO -} from '@utils/constants'; - -import { extractNewSetTokenAddressFromLogs } from '@utils/contract_logs/core'; -import { expectRevertError } from '@utils/tokenAssertions'; -import { getWeb3 } from '@utils/web3Helper'; - -import { ERC20Helper } from '@utils/helpers/erc20Helper'; -import { ManagerHelper } from '@utils/helpers/managerHelper'; -import { OracleHelper } from '@utils/helpers/oracleHelper'; -import { ProtocolHelper } from '@utils/helpers/protocolHelper'; - -BigNumberSetup.configure(); -ChaiSetup.configure(); -const web3 = getWeb3(); -const { expect } = chai; -const blockchain = new Blockchain(web3); -const { SetProtocolTestUtils: SetTestUtils } = setProtocolUtils; -const setTestUtils = new SetTestUtils(web3); - -contract('Integration: TriggerIndexManager', accounts => { - const [ - deployerAccount, - ] = accounts; - - let rebalancingSetToken: RebalancingSetTokenContract; - - let core: CoreContract; - let transferProxy: TransferProxyContract; - let factory: SetTokenFactoryContract; - let rebalancingFactory: RebalancingSetTokenFactoryContract; - let linearAuctionPriceCurve: LinearAuctionPriceCurveContract; - let whiteList: WhiteListContract; - let usdcMock: USDCMockContract; - let wrappedETH: WethMockContract; - - let ethMedianizer: MedianContract; - let legacyMakerOracleAdapter: LegacyMakerOracleAdapterContract; - let oracleProxy: OracleProxyContract; - let usdcOracle: ConstantPriceOracleContract; - let timeSeriesFeed: LinearizedEMATimeSeriesFeedContract; - let emaOracle: EMAOracleContract; - - let trigger: MovingAverageToAssetPriceCrossoverTriggerContract; - let allocator: BinaryAllocatorContract; - - let setManager: TriggerIndexManagerContract; - let quoteAssetCollateral: SetTokenContract; - let baseAssetCollateral: SetTokenContract; - - let initialEthPrice: BigNumber; - let usdcPrice: BigNumber; - let timePeriod: BigNumber; - - let signalConfirmationMinTime: BigNumber; - let signalConfirmationMaxTime: BigNumber; - let initialState: boolean = true; - - const protocolHelper = new ProtocolHelper(deployerAccount); - const erc20Helper = new ERC20Helper(deployerAccount); - const managerHelper = new ManagerHelper(deployerAccount); - const oracleHelper = new OracleHelper(deployerAccount); - - before(async () => { - ABIDecoder.addABI(Core.abi); - }); - - after(async () => { - ABIDecoder.removeABI(Core.abi); - }); - - beforeEach(async () => { - blockchain.saveSnapshotAsync(); - - transferProxy = await protocolHelper.getDeployedTransferProxyAsync(); - core = await protocolHelper.getDeployedCoreAsync(); - - factory = await protocolHelper.getDeployedSetTokenFactoryAsync(); - rebalancingFactory = await protocolHelper.getDeployedRebalancingSetTokenFactoryAsync(); - linearAuctionPriceCurve = await protocolHelper.getDeployedLinearAuctionPriceCurveAsync(); - whiteList = await protocolHelper.getDeployedWhiteList(); - - ethMedianizer = await protocolHelper.getDeployedWETHMedianizerAsync(); - await oracleHelper.addPriceFeedOwnerToMedianizer(ethMedianizer, deployerAccount); - - initialEthPrice = ether(150); - await oracleHelper.updateMedianizerPriceAsync( - ethMedianizer, - initialEthPrice, - SetTestUtils.generateTimestamp(1000), - ); - - usdcMock = await erc20Helper.deployUSDCTokenAsync(deployerAccount); - await protocolHelper.addTokenToWhiteList(usdcMock.address, whiteList); - await blockchain.increaseTimeAsync(ONE); - await protocolHelper.addTokenToWhiteList(usdcMock.address, whiteList); - - wrappedETH = await protocolHelper.getDeployedWETHAsync(); - await erc20Helper.approveTransfersAsync( - [usdcMock, wrappedETH], - transferProxy.address - ); - - legacyMakerOracleAdapter = await oracleHelper.deployLegacyMakerOracleAdapterAsync( - ethMedianizer.address, - ); - - oracleProxy = await oracleHelper.deployOracleProxyAsync( - legacyMakerOracleAdapter.address, - ); - - usdcPrice = ether(1); - usdcOracle = await oracleHelper.deployConstantPriceOracleAsync(usdcPrice); - - timePeriod = new BigNumber(26); - const seededValues = [initialEthPrice]; - timeSeriesFeed = await oracleHelper.deployLinearizedEMATimeSeriesFeedAsync( - oracleProxy.address, - timePeriod, - seededValues - ); - - emaOracle = await oracleHelper.deployEMAOracleAsync( - [timeSeriesFeed.address], - [timePeriod], - ); - - quoteAssetCollateral = await protocolHelper.createSetTokenAsync( - core, - factory.address, - [usdcMock.address], - [new BigNumber(128)], - STABLE_COLLATERAL_NATURAL_UNIT, - ); - - baseAssetCollateral = await protocolHelper.createSetTokenAsync( - core, - factory.address, - [wrappedETH.address], - [new BigNumber(1048576)], - RISK_COLLATERAL_NATURAL_UNIT, - ); - - signalConfirmationMinTime = ONE_HOUR_IN_SECONDS.mul(6); - signalConfirmationMaxTime = ONE_HOUR_IN_SECONDS.mul(12); - trigger = await managerHelper.deployMovingAverageToAssetPriceCrossoverTrigger( - emaOracle.address, - oracleProxy.address, - timePeriod, - initialState, - signalConfirmationMinTime, - signalConfirmationMaxTime - ); - - allocator = await managerHelper.deployBinaryAllocatorAsync( - wrappedETH.address, - usdcMock.address, - oracleProxy.address, - usdcOracle.address, - baseAssetCollateral.address, - quoteAssetCollateral.address, - core.address, - factory.address - ); - - await oracleHelper.addAuthorizedAddressesToOracleProxy( - oracleProxy, - [timeSeriesFeed.address, allocator.address, trigger.address] - ); - }); - - afterEach(async () => { - blockchain.revertAsync(); - }); - - describe('#propose', async () => { - let subjectTimeFastForward: BigNumber; - let subjectCaller: Address; - - let triggerPrice: BigNumber; - let updateMarketState: boolean; - - let baseAssetAllocation: BigNumber; - let auctionStartPercentage: BigNumber; - let auctionEndPercentage: BigNumber; - let auctionTimeToPivot: BigNumber; - - let collateralSetAddress: Address; - let proposalPeriod: BigNumber; - - before(async () => { - triggerPrice = ether(140); - baseAssetAllocation = new BigNumber(100); - updateMarketState = true; - }); - - beforeEach(async () => { - const allocationPrecision = new BigNumber(100); - auctionStartPercentage = new BigNumber(2); - auctionEndPercentage = new BigNumber(10); - auctionTimeToPivot = ONE_HOUR_IN_SECONDS.mul(4); - setManager = await managerHelper.deployTriggerIndexManagerAsync( - core.address, - allocator.address, - linearAuctionPriceCurve.address, - baseAssetAllocation, - allocationPrecision, - auctionStartPercentage, - auctionEndPercentage, - auctionTimeToPivot, - [trigger.address], - [new BigNumber(100)], - subjectCaller, - ); - - collateralSetAddress = baseAssetAllocation.equals(ZERO) ? quoteAssetCollateral.address - : baseAssetCollateral.address; - - proposalPeriod = ONE_DAY_IN_SECONDS; - rebalancingSetToken = await protocolHelper.createDefaultRebalancingSetTokenAsync( - core, - rebalancingFactory.address, - setManager.address, - collateralSetAddress, - proposalPeriod - ); - - await setManager.initialize.sendTransactionAsync( - rebalancingSetToken.address, - { from: subjectCaller, gas: DEFAULT_GAS} - ); - - if (updateMarketState) { - const lastBlockInfo = await web3.eth.getBlock('latest'); - await oracleHelper.updateMedianizerPriceAsync( - ethMedianizer, - triggerPrice, - new BigNumber(lastBlockInfo.timestamp + 1), - ); - - await trigger.initialTrigger.sendTransactionAsync(); - - await blockchain.increaseTimeAsync(signalConfirmationMinTime.add(1)); - await trigger.confirmTrigger.sendTransactionAsync(); - } - - subjectTimeFastForward = ONE_DAY_IN_SECONDS.add(1); - subjectCaller = deployerAccount; - }); - - async function subject(): Promise { - await blockchain.increaseTimeAsync(subjectTimeFastForward); - return setManager.propose.sendTransactionAsync( - { from: subjectCaller, gas: DEFAULT_GAS} - ); - } - - describe('when propose is called from the Default state', async () => { - describe('and allocating from base asset to quote asset', async () => { - it('updates to the next set correctly', async () => { - await subject(); - - const actualNextSet = await rebalancingSetToken.nextSet.callAsync(); - expect(actualNextSet).to.equal(quoteAssetCollateral.address); - }); - - it('updates to the new auction library correctly', async () => { - await subject(); - - const newAuctionLibrary = await rebalancingSetToken.auctionLibrary.callAsync(); - expect(newAuctionLibrary).to.equal(linearAuctionPriceCurve.address); - }); - - it('updates the time to pivot correctly', async () => { - await subject(); - - const auctionPriceParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionTimeToPivot = auctionPriceParameters[1]; - expect(newAuctionTimeToPivot).to.be.bignumber.equal(auctionTimeToPivot); - }); - - it('updates the auction start price correctly', async () => { - await subject(); - - const baseCollateralValue = await managerHelper.calculateSetTokenValue( - baseAssetCollateral, - [triggerPrice], - [ETH_DECIMALS], - ); - - const quoteCollateralValue = await managerHelper.calculateSetTokenValue( - quoteAssetCollateral, - [ether(1)], - [USDC_DECIMALS], - ); - - const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( - baseCollateralValue, - quoteCollateralValue, - auctionStartPercentage, - auctionEndPercentage - ); - - const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionStartPrice = newAuctionParameters[2]; - - expect(newAuctionStartPrice).to.be.bignumber.equal(auctionPriceParameters['auctionStartPrice']); - }); - - it('updates the auction pivot price correctly', async () => { - await subject(); - - const baseCollateralValue = await managerHelper.calculateSetTokenValue( - baseAssetCollateral, - [triggerPrice], - [ETH_DECIMALS], - ); - - const quoteCollateralValue = await managerHelper.calculateSetTokenValue( - quoteAssetCollateral, - [ether(1)], - [USDC_DECIMALS], - ); - - const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( - baseCollateralValue, - quoteCollateralValue, - auctionStartPercentage, - auctionEndPercentage - ); - - const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionPivotPrice = newAuctionParameters[3]; - - expect(newAuctionPivotPrice).to.be.bignumber.equal(auctionPriceParameters['auctionPivotPrice']); - }); - - describe('but quote collateral is 4x valuable than base collateral', async () => { - before(async () => { - triggerPrice = ether(25); - }); - - it('should pass correct next set address', async () => { - const txHash = await subject(); - - const logs = await setTestUtils.getLogsFromTxHash(txHash); - const expectedNextSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); - - const actualNextSetAddress = await rebalancingSetToken.nextSet.callAsync(); - expect(actualNextSetAddress).to.equal(expectedNextSetAddress); - }); - - it('updates new quote collateral to the correct naturalUnit', async () => { - await subject(); - - const nextSetAddress = await rebalancingSetToken.nextSet.callAsync(); - const nextSet = await protocolHelper.getSetTokenAsync(nextSetAddress); - const nextSetNaturalUnit = await nextSet.naturalUnit.callAsync(); - - const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( - baseAssetCollateral, - triggerPrice, - usdcPrice, - ETH_DECIMALS, - USDC_DECIMALS, - ); - expect(nextSetNaturalUnit).to.be.bignumber.equal(expectedNextSetParams['naturalUnit']); - }); - - it('updates new quote collateral to the correct units', async () => { - await subject(); - - const nextSetAddress = await rebalancingSetToken.nextSet.callAsync(); - const nextSet = await protocolHelper.getSetTokenAsync(nextSetAddress); - const nextSetUnits = await nextSet.getUnits.callAsync(); - - const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( - baseAssetCollateral, - triggerPrice, - usdcPrice, - ETH_DECIMALS, - USDC_DECIMALS, - ); - expect(JSON.stringify(nextSetUnits)).to.be.eql(JSON.stringify(expectedNextSetParams['units'])); - }); - - it('updates new quote collateral to the correct components', async () => { - await subject(); - - const nextSetAddress = await rebalancingSetToken.nextSet.callAsync(); - const nextSet = await protocolHelper.getSetTokenAsync(nextSetAddress); - const nextSetComponents = await nextSet.getComponents.callAsync(); - - const expectedNextSetComponents = [usdcMock.address]; - expect(JSON.stringify(nextSetComponents)).to.be.eql(JSON.stringify(expectedNextSetComponents)); - }); - - it('updates the auction start price correctly', async () => { - const txHash = await subject(); - - const logs = await setTestUtils.getLogsFromTxHash(txHash); - const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - - const baseCollateralValue = await managerHelper.calculateSetTokenValue( - baseAssetCollateral, - [triggerPrice], - [ETH_DECIMALS], - ); - - const quoteCollateralValue = await managerHelper.calculateSetTokenValue( - newSet, - [ether(1)], - [USDC_DECIMALS], - ); - - const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( - baseCollateralValue, - quoteCollateralValue, - auctionStartPercentage, - auctionEndPercentage - ); - - const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionStartPrice = newAuctionParameters[2]; - - expect(newAuctionStartPrice).to.be.bignumber.equal(auctionPriceParameters['auctionStartPrice']); - }); - - it('updates the auction pivot price correctly', async () => { - const txHash = await subject(); - - const logs = await setTestUtils.getLogsFromTxHash(txHash); - const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - - const baseCollateralValue = await managerHelper.calculateSetTokenValue( - baseAssetCollateral, - [triggerPrice], - [ETH_DECIMALS], - ); - - const quoteCollateralValue = await managerHelper.calculateSetTokenValue( - newSet, - [ether(1)], - [USDC_DECIMALS], - ); - - const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( - baseCollateralValue, - quoteCollateralValue, - auctionStartPercentage, - auctionEndPercentage - ); - - const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionPivotPrice = newAuctionParameters[3]; - - expect(newAuctionPivotPrice).to.be.bignumber.equal(auctionPriceParameters['auctionPivotPrice']); - }); - }); - - describe('but new stable collateral requires bump in natural unit', async () => { - before(async () => { - triggerPrice = ether(.4); - }); - - it('should pass correct next set address', async () => { - const txHash = await subject(); - - const logs = await setTestUtils.getLogsFromTxHash(txHash); - const expectedNextSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); - - const actualNextSetAddress = await rebalancingSetToken.nextSet.callAsync(); - expect(actualNextSetAddress).to.equal(expectedNextSetAddress); - }); - - it('updates new stable collateral to the correct naturalUnit', async () => { - await subject(); - - const newSetAddress = await rebalancingSetToken.nextSet.callAsync(); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - const newSetNaturalUnit = await newSet.naturalUnit.callAsync(); - - const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( - baseAssetCollateral, - triggerPrice, - usdcPrice, - ETH_DECIMALS, - USDC_DECIMALS, - ); - expect(newSetNaturalUnit).to.be.bignumber.equal(expectedNextSetParams['naturalUnit']); - }); - - it('updates new stable collateral to the correct units', async () => { - await subject(); - - const newSetAddress = await rebalancingSetToken.nextSet.callAsync(); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - const newSetUnits = await newSet.getUnits.callAsync(); - - const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( - baseAssetCollateral, - triggerPrice, - usdcPrice, - ETH_DECIMALS, - USDC_DECIMALS, - ); - expect(JSON.stringify(newSetUnits)).to.be.eql(JSON.stringify(expectedNextSetParams['units'])); - }); - - it('updates new stable collateral to the correct components', async () => { - await subject(); - - const nextSetAddress = await rebalancingSetToken.nextSet.callAsync(); - const nextSet = await protocolHelper.getSetTokenAsync(nextSetAddress); - const nextSetComponents = await nextSet.getComponents.callAsync(); - - const expectedNextSetComponents = [usdcMock.address]; - expect(JSON.stringify(nextSetComponents)).to.be.eql(JSON.stringify(expectedNextSetComponents)); - }); - - it('updates the auction start price correctly', async () => { - const txHash = await subject(); - - const logs = await setTestUtils.getLogsFromTxHash(txHash); - const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - - const baseCollateralValue = await managerHelper.calculateSetTokenValue( - baseAssetCollateral, - [triggerPrice], - [ETH_DECIMALS], - ); - - const quoteCollateralValue = await managerHelper.calculateSetTokenValue( - newSet, - [ether(1)], - [USDC_DECIMALS], - ); - - const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( - baseCollateralValue, - quoteCollateralValue, - auctionStartPercentage, - auctionEndPercentage - ); - - const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionStartPrice = newAuctionParameters[2]; - - expect(newAuctionStartPrice).to.be.bignumber.equal(auctionPriceParameters['auctionStartPrice']); - }); - - it('updates the auction pivot price correctly', async () => { - const txHash = await subject(); - - const logs = await setTestUtils.getLogsFromTxHash(txHash); - const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - - const baseCollateralValue = await managerHelper.calculateSetTokenValue( - baseAssetCollateral, - [triggerPrice], - [ETH_DECIMALS], - ); - - const quoteCollateralValue = await managerHelper.calculateSetTokenValue( - newSet, - [ether(1)], - [USDC_DECIMALS], - ); - - const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( - baseCollateralValue, - quoteCollateralValue, - auctionStartPercentage, - auctionEndPercentage - ); - - const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionPivotPrice = newAuctionParameters[3]; - - expect(newAuctionPivotPrice).to.be.bignumber.equal(auctionPriceParameters['auctionPivotPrice']); - }); - }); - - describe('but price has not dipped below MA', async () => { - before(async () => { - updateMarketState = false; - }); - - after(async () => { - updateMarketState = true; - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - - describe('but not enough time has passed from last rebalance', async () => { - beforeEach(async () => { - subjectTimeFastForward = ZERO; - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - }); - - describe('and allocating from quote asset to base asset', async () => { - before(async () => { - initialState = false; - baseAssetAllocation = ZERO; - triggerPrice = ether(170); - }); - - it('updates to the next set correctly', async () => { - await subject(); - - const actualNextSet = await rebalancingSetToken.nextSet.callAsync(); - expect(actualNextSet).to.equal(baseAssetCollateral.address); - }); - - it('updates to the new auction library correctly', async () => { - await subject(); - - const newAuctionLibrary = await rebalancingSetToken.auctionLibrary.callAsync(); - expect(newAuctionLibrary).to.equal(linearAuctionPriceCurve.address); - }); - - it('updates the time to pivot correctly', async () => { - await subject(); - - const auctionPriceParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionTimeToPivot = auctionPriceParameters[1]; - expect(newAuctionTimeToPivot).to.be.bignumber.equal(auctionTimeToPivot); - }); - - it('updates the auction start price correctly', async () => { - await subject(); - - const baseCollateralValue = await managerHelper.calculateSetTokenValue( - baseAssetCollateral, - [triggerPrice], - [ETH_DECIMALS], - ); - - const quoteCollateralValue = await managerHelper.calculateSetTokenValue( - quoteAssetCollateral, - [ether(1)], - [USDC_DECIMALS], - ); - - const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( - quoteCollateralValue, - baseCollateralValue, - auctionStartPercentage, - auctionEndPercentage - ); - - const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionStartPrice = newAuctionParameters[2]; - - expect(newAuctionStartPrice).to.be.bignumber.equal(auctionPriceParameters['auctionStartPrice']); - }); - - it('updates the auction pivot price correctly', async () => { - await subject(); - - const baseCollateralValue = await managerHelper.calculateSetTokenValue( - baseAssetCollateral, - [triggerPrice], - [ETH_DECIMALS], - ); - - const quoteCollateralValue = await managerHelper.calculateSetTokenValue( - quoteAssetCollateral, - [ether(1)], - [USDC_DECIMALS], - ); - - const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( - quoteCollateralValue, - baseCollateralValue, - auctionStartPercentage, - auctionEndPercentage - ); - - const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionPivotPrice = newAuctionParameters[3]; - - expect(newAuctionPivotPrice).to.be.bignumber.equal(auctionPriceParameters['auctionPivotPrice']); - }); - - describe('but baseAsset collateral is 4x valuable than quoteAsset collateral', async () => { - before(async () => { - triggerPrice = ether(400); - }); - - it('should pass correct next set address', async () => { - const txHash = await subject(); - - const logs = await setTestUtils.getLogsFromTxHash(txHash); - const expectedNextSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); - - const actualNextSetAddress = await rebalancingSetToken.nextSet.callAsync(); - expect(actualNextSetAddress).to.equal(expectedNextSetAddress); - }); - - it('updates new risk collateral to the correct naturalUnit', async () => { - await subject(); - - const newSetAddress = await rebalancingSetToken.nextSet.callAsync(); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - const newSetNaturalUnit = await newSet.naturalUnit.callAsync(); - - const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( - quoteAssetCollateral, - usdcPrice, - triggerPrice, - USDC_DECIMALS, - ETH_DECIMALS, - ); - expect(newSetNaturalUnit).to.be.bignumber.equal(expectedNextSetParams['naturalUnit']); - }); - - it('updates new risk collateral to the correct units', async () => { - await subject(); - - const newSetAddress = await rebalancingSetToken.nextSet.callAsync(); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - const newSetUnits = await newSet.getUnits.callAsync(); - - const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( - quoteAssetCollateral, - usdcPrice, - triggerPrice, - USDC_DECIMALS, - ETH_DECIMALS, - ); - expect(JSON.stringify(newSetUnits)).to.be.eql(JSON.stringify(expectedNextSetParams['units'])); - }); - - it('updates new risk collateral to the correct components', async () => { - await subject(); - - const nextSetAddress = await rebalancingSetToken.nextSet.callAsync(); - const nextSet = await protocolHelper.getSetTokenAsync(nextSetAddress); - const nextSetComponents = await nextSet.getComponents.callAsync(); - - const expectedNextSetComponents = [wrappedETH.address]; - expect(JSON.stringify(nextSetComponents)).to.be.eql(JSON.stringify(expectedNextSetComponents)); - }); - - it('updates the auction start price correctly', async () => { - const txHash = await subject(); - - const logs = await setTestUtils.getLogsFromTxHash(txHash); - const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - - const baseCollateralValue = await managerHelper.calculateSetTokenValue( - newSet, - [triggerPrice], - [ETH_DECIMALS], - ); - - const quoteCollateralValue = await managerHelper.calculateSetTokenValue( - quoteAssetCollateral, - [ether(1)], - [USDC_DECIMALS], - ); - - const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( - quoteCollateralValue, - baseCollateralValue, - auctionStartPercentage, - auctionEndPercentage - ); - - const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionStartPrice = newAuctionParameters[2]; - - expect(newAuctionStartPrice).to.be.bignumber.equal(auctionPriceParameters['auctionStartPrice']); - }); - - it('updates the auction pivot price correctly', async () => { - const txHash = await subject(); - - const logs = await setTestUtils.getLogsFromTxHash(txHash); - const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - - const baseCollateralValue = await managerHelper.calculateSetTokenValue( - newSet, - [triggerPrice], - [ETH_DECIMALS], - ); - - const quoteCollateralValue = await managerHelper.calculateSetTokenValue( - quoteAssetCollateral, - [ether(1)], - [USDC_DECIMALS], - ); - - const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( - quoteCollateralValue, - baseCollateralValue, - auctionStartPercentage, - auctionEndPercentage - ); - - const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionPivotPrice = newAuctionParameters[3]; - - expect(newAuctionPivotPrice).to.be.bignumber.equal(auctionPriceParameters['auctionPivotPrice']); - }); - }); - - describe('but new risk collateral requires bump in natural unit', async () => { - before(async () => { - triggerPrice = ether(3 * 10 ** 8); - }); - - it('should pass correct next set address', async () => { - const txHash = await subject(); - - const logs = await setTestUtils.getLogsFromTxHash(txHash); - const expectedNextSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); - - const actualNextSetAddress = await rebalancingSetToken.nextSet.callAsync(); - expect(actualNextSetAddress).to.equal(expectedNextSetAddress); - }); - - it('updates new risk collateral to the correct naturalUnit', async () => { - await subject(); - - const newSetAddress = await rebalancingSetToken.nextSet.callAsync(); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - const newSetNaturalUnit = await newSet.naturalUnit.callAsync(); - - const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( - quoteAssetCollateral, - usdcPrice, - triggerPrice, - USDC_DECIMALS, - ETH_DECIMALS, - ); - - expect(newSetNaturalUnit).to.be.bignumber.equal(expectedNextSetParams['naturalUnit']); - }); - - it('updates new risk collateral to the correct units', async () => { - await subject(); - - const newSetAddress = await rebalancingSetToken.nextSet.callAsync(); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - const newSetUnits = await newSet.getUnits.callAsync(); - - const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( - quoteAssetCollateral, - usdcPrice, - triggerPrice, - USDC_DECIMALS, - ETH_DECIMALS, - ); - expect(JSON.stringify(newSetUnits)).to.be.eql(JSON.stringify(expectedNextSetParams['units'])); - }); - - it('updates new risk collateral to the correct components', async () => { - await subject(); - - const nextSetAddress = await rebalancingSetToken.nextSet.callAsync(); - const nextSet = await protocolHelper.getSetTokenAsync(nextSetAddress); - const nextSetComponents = await nextSet.getComponents.callAsync(); - - const expectedNextSetComponents = [wrappedETH.address]; - expect(JSON.stringify(nextSetComponents)).to.be.eql(JSON.stringify(expectedNextSetComponents)); - }); - - it('updates the auction start price correctly', async () => { - const txHash = await subject(); - - const logs = await setTestUtils.getLogsFromTxHash(txHash); - const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - - const baseCollateralValue = await managerHelper.calculateSetTokenValue( - newSet, - [triggerPrice], - [ETH_DECIMALS], - ); - - const quoteCollateralValue = await managerHelper.calculateSetTokenValue( - quoteAssetCollateral, - [ether(1)], - [USDC_DECIMALS], - ); - - const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( - quoteCollateralValue, - baseCollateralValue, - auctionStartPercentage, - auctionEndPercentage - ); - - const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionStartPrice = newAuctionParameters[2]; - - expect(newAuctionStartPrice).to.be.bignumber.equal(auctionPriceParameters['auctionStartPrice']); - }); - - it('updates the auction pivot price correctly', async () => { - const txHash = await subject(); - - const logs = await setTestUtils.getLogsFromTxHash(txHash); - const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); - const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); - - const baseCollateralValue = await managerHelper.calculateSetTokenValue( - newSet, - [triggerPrice], - [ETH_DECIMALS], - ); - - const quoteCollateralValue = await managerHelper.calculateSetTokenValue( - quoteAssetCollateral, - [ether(1)], - [USDC_DECIMALS], - ); - - const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( - quoteCollateralValue, - baseCollateralValue, - auctionStartPercentage, - auctionEndPercentage - ); - - const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); - const newAuctionPivotPrice = newAuctionParameters[3]; - - expect(newAuctionPivotPrice).to.be.bignumber.equal(auctionPriceParameters['auctionPivotPrice']); - }); - }); - - describe('but price has not gone above MA', async () => { - before(async () => { - updateMarketState = false; - }); - - after(async () => { - updateMarketState = true; - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - - describe('but not enough time has passed from last rebalance', async () => { - beforeEach(async () => { - subjectTimeFastForward = ZERO; - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - }); - }); - - describe('when propose is called and rebalancing set token is in Proposal state', async () => { - beforeEach(async () => { - await blockchain.increaseTimeAsync(subjectTimeFastForward); - await setManager.propose.sendTransactionAsync(); - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - - describe('when propose is called and rebalancing set token is in Rebalance state', async () => { - beforeEach(async () => { - // Issue currentSetToken - const initialAllocationTokenAddress = await rebalancingSetToken.currentSet.callAsync(); - const initialAllocationToken = await protocolHelper.getSetTokenAsync(initialAllocationTokenAddress); - await core.issue.sendTransactionAsync( - initialAllocationToken.address, - ether(9), - {from: deployerAccount, gas: DEFAULT_GAS}, - ); - await erc20Helper.approveTransfersAsync([initialAllocationToken], transferProxy.address); - - // Use issued currentSetToken to issue rebalancingSetToken - await core.issue.sendTransactionAsync( - rebalancingSetToken.address, - ether(7), - { from: deployerAccount, gas: DEFAULT_GAS } - ); - - await blockchain.increaseTimeAsync(subjectTimeFastForward); - await setManager.propose.sendTransactionAsync(); - - await blockchain.increaseTimeAsync(ONE_DAY_IN_SECONDS); - await rebalancingSetToken.startRebalance.sendTransactionAsync(); - }); - - it('should revert', async () => { - await expectRevertError(subject()); - }); - }); - }); -}); \ No newline at end of file +// require('module-alias/register'); + +// import * as _ from 'lodash'; +// import * as ABIDecoder from 'abi-decoder'; +// import * as chai from 'chai'; +// import * as setProtocolUtils from 'set-protocol-utils'; + +// import { Address } from 'set-protocol-utils'; +// import { BigNumber } from 'bignumber.js'; + +// import ChaiSetup from '@utils/chaiSetup'; +// import { BigNumberSetup } from '@utils/bigNumberSetup'; +// import { Blockchain } from '@utils/blockchain'; +// import { ether } from '@utils/units'; +// import { +// Core, +// CoreContract, +// LinearAuctionPriceCurveContract, +// MedianContract, +// RebalancingSetTokenContract, +// RebalancingSetTokenFactoryContract, +// SetTokenContract, +// SetTokenFactoryContract, +// TransferProxyContract, +// WethMockContract, +// WhiteListContract, +// } from 'set-protocol-contracts'; +// import { +// BinaryAllocatorContract, +// ConstantPriceOracleContract, +// EMAOracleContract, +// LegacyMakerOracleAdapterContract, +// LinearizedEMATimeSeriesFeedContract, +// MovingAverageCrossoverTriggerContract, +// OracleProxyContract, +// TriggerIndexManagerContract, +// USDCMockContract, +// } from '@utils/contracts'; + +// import { +// DEFAULT_GAS, +// ETH_DECIMALS, +// ONE, +// ONE_DAY_IN_SECONDS, +// ONE_HOUR_IN_SECONDS, +// RISK_COLLATERAL_NATURAL_UNIT, +// STABLE_COLLATERAL_NATURAL_UNIT, +// USDC_DECIMALS, +// ZERO +// } from '@utils/constants'; + +// import { extractNewSetTokenAddressFromLogs } from '@utils/contract_logs/core'; +// import { expectRevertError } from '@utils/tokenAssertions'; +// import { getWeb3 } from '@utils/web3Helper'; + +// import { ERC20Helper } from '@utils/helpers/erc20Helper'; +// import { ManagerHelper } from '@utils/helpers/managerHelper'; +// import { OracleHelper } from '@utils/helpers/oracleHelper'; +// import { ProtocolHelper } from '@utils/helpers/protocolHelper'; + +// BigNumberSetup.configure(); +// ChaiSetup.configure(); +// const web3 = getWeb3(); +// const { expect } = chai; +// const blockchain = new Blockchain(web3); +// const { SetProtocolTestUtils: SetTestUtils } = setProtocolUtils; +// const setTestUtils = new SetTestUtils(web3); + +// contract('Integration: TriggerIndexManager', accounts => { +// const [ +// deployerAccount, +// ] = accounts; + +// let rebalancingSetToken: RebalancingSetTokenContract; + +// let core: CoreContract; +// let transferProxy: TransferProxyContract; +// let factory: SetTokenFactoryContract; +// let rebalancingFactory: RebalancingSetTokenFactoryContract; +// let linearAuctionPriceCurve: LinearAuctionPriceCurveContract; +// let whiteList: WhiteListContract; +// let usdcMock: USDCMockContract; +// let wrappedETH: WethMockContract; + +// let ethMedianizer: MedianContract; +// let legacyMakerOracleAdapter: LegacyMakerOracleAdapterContract; +// let oracleProxy: OracleProxyContract; +// let usdcOracle: ConstantPriceOracleContract; +// let timeSeriesFeed: LinearizedEMATimeSeriesFeedContract; +// let emaOracle: EMAOracleContract; + +// let trigger: MovingAverageCrossoverTriggerContract; +// let allocator: BinaryAllocatorContract; + +// let setManager: TriggerIndexManagerContract; +// let quoteAssetCollateral: SetTokenContract; +// let baseAssetCollateral: SetTokenContract; + +// let initialEthPrice: BigNumber; +// let usdcPrice: BigNumber; +// let timePeriod: BigNumber; + +// const protocolHelper = new ProtocolHelper(deployerAccount); +// const erc20Helper = new ERC20Helper(deployerAccount); +// const managerHelper = new ManagerHelper(deployerAccount); +// const oracleHelper = new OracleHelper(deployerAccount); + +// before(async () => { +// ABIDecoder.addABI(Core.abi); +// }); + +// after(async () => { +// ABIDecoder.removeABI(Core.abi); +// }); + +// beforeEach(async () => { +// blockchain.saveSnapshotAsync(); + +// transferProxy = await protocolHelper.getDeployedTransferProxyAsync(); +// core = await protocolHelper.getDeployedCoreAsync(); + +// factory = await protocolHelper.getDeployedSetTokenFactoryAsync(); +// rebalancingFactory = await protocolHelper.getDeployedRebalancingSetTokenFactoryAsync(); +// linearAuctionPriceCurve = await protocolHelper.getDeployedLinearAuctionPriceCurveAsync(); +// whiteList = await protocolHelper.getDeployedWhiteList(); + +// ethMedianizer = await protocolHelper.getDeployedWETHMedianizerAsync(); +// await oracleHelper.addPriceFeedOwnerToMedianizer(ethMedianizer, deployerAccount); + +// initialEthPrice = ether(150); +// await oracleHelper.updateMedianizerPriceAsync( +// ethMedianizer, +// initialEthPrice, +// SetTestUtils.generateTimestamp(1000), +// ); + +// usdcMock = await erc20Helper.deployUSDCTokenAsync(deployerAccount); +// await protocolHelper.addTokenToWhiteList(usdcMock.address, whiteList); +// await blockchain.increaseTimeAsync(ONE); +// await protocolHelper.addTokenToWhiteList(usdcMock.address, whiteList); + +// wrappedETH = await protocolHelper.getDeployedWETHAsync(); +// await erc20Helper.approveTransfersAsync( +// [usdcMock, wrappedETH], +// transferProxy.address +// ); + +// legacyMakerOracleAdapter = await oracleHelper.deployLegacyMakerOracleAdapterAsync( +// ethMedianizer.address, +// ); + +// oracleProxy = await oracleHelper.deployOracleProxyAsync( +// legacyMakerOracleAdapter.address, +// ); + +// usdcPrice = ether(1); +// usdcOracle = await oracleHelper.deployConstantPriceOracleAsync(usdcPrice); + +// timePeriod = new BigNumber(26); +// const seededValues = [initialEthPrice]; +// timeSeriesFeed = await oracleHelper.deployLinearizedEMATimeSeriesFeedAsync( +// oracleProxy.address, +// timePeriod, +// seededValues +// ); + +// emaOracle = await oracleHelper.deployEMAOracleAsync( +// [timeSeriesFeed.address], +// [timePeriod], +// ); + +// quoteAssetCollateral = await protocolHelper.createSetTokenAsync( +// core, +// factory.address, +// [usdcMock.address], +// [new BigNumber(128)], +// STABLE_COLLATERAL_NATURAL_UNIT, +// ); + +// baseAssetCollateral = await protocolHelper.createSetTokenAsync( +// core, +// factory.address, +// [wrappedETH.address], +// [new BigNumber(1048576)], +// RISK_COLLATERAL_NATURAL_UNIT, +// ); + +// trigger = await managerHelper.deployMovingAverageCrossoverTrigger( +// emaOracle.address, +// oracleProxy.address, +// timePeriod, +// ); + +// allocator = await managerHelper.deployBinaryAllocatorAsync( +// wrappedETH.address, +// usdcMock.address, +// oracleProxy.address, +// usdcOracle.address, +// baseAssetCollateral.address, +// quoteAssetCollateral.address, +// core.address, +// factory.address +// ); + +// await oracleHelper.addAuthorizedAddressesToOracleProxy( +// oracleProxy, +// [timeSeriesFeed.address, allocator.address, trigger.address] +// ); +// }); + +// afterEach(async () => { +// blockchain.revertAsync(); +// }); + +// describe('#propose', async () => { +// let subjectTimeFastForward: BigNumber; +// let subjectCaller: Address; + +// let triggerPrice: BigNumber; +// let updateMarketState: boolean; + +// let baseAssetAllocation: BigNumber; +// let auctionStartPercentage: BigNumber; +// let auctionEndPercentage: BigNumber; +// let auctionTimeToPivot: BigNumber; + +// let collateralSetAddress: Address; +// let proposalPeriod: BigNumber; + +// before(async () => { +// triggerPrice = ether(140); +// baseAssetAllocation = new BigNumber(100); +// updateMarketState = true; +// }); + +// beforeEach(async () => { +// const allocationPrecision = new BigNumber(100); +// auctionStartPercentage = new BigNumber(2); +// auctionEndPercentage = new BigNumber(10); +// auctionTimeToPivot = ONE_HOUR_IN_SECONDS.mul(4); +// setManager = await managerHelper.deployTriggerIndexManagerAsync( +// core.address, +// allocator.address, +// linearAuctionPriceCurve.address, +// baseAssetAllocation, +// allocationPrecision, +// auctionStartPercentage, +// auctionEndPercentage, +// auctionTimeToPivot, +// [trigger.address], +// [new BigNumber(100)], +// subjectCaller, +// ); + +// collateralSetAddress = baseAssetAllocation.equals(ZERO) ? quoteAssetCollateral.address +// : baseAssetCollateral.address; + +// proposalPeriod = ONE_DAY_IN_SECONDS; +// rebalancingSetToken = await protocolHelper.createDefaultRebalancingSetTokenAsync( +// core, +// rebalancingFactory.address, +// setManager.address, +// collateralSetAddress, +// proposalPeriod +// ); + +// await setManager.initialize.sendTransactionAsync( +// rebalancingSetToken.address, +// { from: subjectCaller, gas: DEFAULT_GAS} +// ); + +// if (updateMarketState) { +// const lastBlockInfo = await web3.eth.getBlock('latest'); +// await oracleHelper.updateMedianizerPriceAsync( +// ethMedianizer, +// triggerPrice, +// new BigNumber(lastBlockInfo.timestamp + 1), +// ); +// } + +// subjectTimeFastForward = ONE_DAY_IN_SECONDS.add(1); +// subjectCaller = deployerAccount; +// }); + +// async function subject(): Promise { +// await blockchain.increaseTimeAsync(subjectTimeFastForward); +// return setManager.propose.sendTransactionAsync( +// { from: subjectCaller, gas: DEFAULT_GAS} +// ); +// } + +// describe('when propose is called from the Default state', async () => { +// describe('and allocating from base asset to quote asset', async () => { +// it('updates to the next set correctly', async () => { +// await subject(); + +// const actualNextSet = await rebalancingSetToken.nextSet.callAsync(); +// expect(actualNextSet).to.equal(quoteAssetCollateral.address); +// }); + +// it('updates to the new auction library correctly', async () => { +// await subject(); + +// const newAuctionLibrary = await rebalancingSetToken.auctionLibrary.callAsync(); +// expect(newAuctionLibrary).to.equal(linearAuctionPriceCurve.address); +// }); + +// it('updates the time to pivot correctly', async () => { +// await subject(); + +// const auctionPriceParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionTimeToPivot = auctionPriceParameters[1]; +// expect(newAuctionTimeToPivot).to.be.bignumber.equal(auctionTimeToPivot); +// }); + +// it('updates the auction start price correctly', async () => { +// await subject(); + +// const baseCollateralValue = await managerHelper.calculateSetTokenValue( +// baseAssetCollateral, +// [triggerPrice], +// [ETH_DECIMALS], +// ); + +// const quoteCollateralValue = await managerHelper.calculateSetTokenValue( +// quoteAssetCollateral, +// [ether(1)], +// [USDC_DECIMALS], +// ); + +// const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( +// baseCollateralValue, +// quoteCollateralValue, +// auctionStartPercentage, +// auctionEndPercentage +// ); + +// const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionStartPrice = newAuctionParameters[2]; + +// expect(newAuctionStartPrice).to.be.bignumber.equal(auctionPriceParameters['auctionStartPrice']); +// }); + +// it('updates the auction pivot price correctly', async () => { +// await subject(); + +// const baseCollateralValue = await managerHelper.calculateSetTokenValue( +// baseAssetCollateral, +// [triggerPrice], +// [ETH_DECIMALS], +// ); + +// const quoteCollateralValue = await managerHelper.calculateSetTokenValue( +// quoteAssetCollateral, +// [ether(1)], +// [USDC_DECIMALS], +// ); + +// const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( +// baseCollateralValue, +// quoteCollateralValue, +// auctionStartPercentage, +// auctionEndPercentage +// ); + +// const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionPivotPrice = newAuctionParameters[3]; + +// expect(newAuctionPivotPrice).to.be.bignumber.equal(auctionPriceParameters['auctionPivotPrice']); +// }); + +// describe('but quote collateral is 4x valuable than base collateral', async () => { +// before(async () => { +// triggerPrice = ether(25); +// }); + +// it('should pass correct next set address', async () => { +// const txHash = await subject(); + +// const logs = await setTestUtils.getLogsFromTxHash(txHash); +// const expectedNextSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); + +// const actualNextSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// expect(actualNextSetAddress).to.equal(expectedNextSetAddress); +// }); + +// it('updates new quote collateral to the correct naturalUnit', async () => { +// await subject(); + +// const nextSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// const nextSet = await protocolHelper.getSetTokenAsync(nextSetAddress); +// const nextSetNaturalUnit = await nextSet.naturalUnit.callAsync(); + +// const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( +// baseAssetCollateral, +// triggerPrice, +// usdcPrice, +// ETH_DECIMALS, +// USDC_DECIMALS, +// ); +// expect(nextSetNaturalUnit).to.be.bignumber.equal(expectedNextSetParams['naturalUnit']); +// }); + +// it('updates new quote collateral to the correct units', async () => { +// await subject(); + +// const nextSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// const nextSet = await protocolHelper.getSetTokenAsync(nextSetAddress); +// const nextSetUnits = await nextSet.getUnits.callAsync(); + +// const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( +// baseAssetCollateral, +// triggerPrice, +// usdcPrice, +// ETH_DECIMALS, +// USDC_DECIMALS, +// ); +// expect(JSON.stringify(nextSetUnits)).to.be.eql(JSON.stringify(expectedNextSetParams['units'])); +// }); + +// it('updates new quote collateral to the correct components', async () => { +// await subject(); + +// const nextSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// const nextSet = await protocolHelper.getSetTokenAsync(nextSetAddress); +// const nextSetComponents = await nextSet.getComponents.callAsync(); + +// const expectedNextSetComponents = [usdcMock.address]; +// expect(JSON.stringify(nextSetComponents)).to.be.eql(JSON.stringify(expectedNextSetComponents)); +// }); + +// it('updates the auction start price correctly', async () => { +// const txHash = await subject(); + +// const logs = await setTestUtils.getLogsFromTxHash(txHash); +// const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); + +// const baseCollateralValue = await managerHelper.calculateSetTokenValue( +// baseAssetCollateral, +// [triggerPrice], +// [ETH_DECIMALS], +// ); + +// const quoteCollateralValue = await managerHelper.calculateSetTokenValue( +// newSet, +// [ether(1)], +// [USDC_DECIMALS], +// ); + +// const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( +// baseCollateralValue, +// quoteCollateralValue, +// auctionStartPercentage, +// auctionEndPercentage +// ); + +// const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionStartPrice = newAuctionParameters[2]; + +// expect(newAuctionStartPrice).to.be.bignumber.equal(auctionPriceParameters['auctionStartPrice']); +// }); + +// it('updates the auction pivot price correctly', async () => { +// const txHash = await subject(); + +// const logs = await setTestUtils.getLogsFromTxHash(txHash); +// const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); + +// const baseCollateralValue = await managerHelper.calculateSetTokenValue( +// baseAssetCollateral, +// [triggerPrice], +// [ETH_DECIMALS], +// ); + +// const quoteCollateralValue = await managerHelper.calculateSetTokenValue( +// newSet, +// [ether(1)], +// [USDC_DECIMALS], +// ); + +// const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( +// baseCollateralValue, +// quoteCollateralValue, +// auctionStartPercentage, +// auctionEndPercentage +// ); + +// const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionPivotPrice = newAuctionParameters[3]; + +// expect(newAuctionPivotPrice).to.be.bignumber.equal(auctionPriceParameters['auctionPivotPrice']); +// }); +// }); + +// describe('but new stable collateral requires bump in natural unit', async () => { +// before(async () => { +// triggerPrice = ether(.4); +// }); + +// it('should pass correct next set address', async () => { +// const txHash = await subject(); + +// const logs = await setTestUtils.getLogsFromTxHash(txHash); +// const expectedNextSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); + +// const actualNextSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// expect(actualNextSetAddress).to.equal(expectedNextSetAddress); +// }); + +// it('updates new stable collateral to the correct naturalUnit', async () => { +// await subject(); + +// const newSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); +// const newSetNaturalUnit = await newSet.naturalUnit.callAsync(); + +// const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( +// baseAssetCollateral, +// triggerPrice, +// usdcPrice, +// ETH_DECIMALS, +// USDC_DECIMALS, +// ); +// expect(newSetNaturalUnit).to.be.bignumber.equal(expectedNextSetParams['naturalUnit']); +// }); + +// it('updates new stable collateral to the correct units', async () => { +// await subject(); + +// const newSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); +// const newSetUnits = await newSet.getUnits.callAsync(); + +// const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( +// baseAssetCollateral, +// triggerPrice, +// usdcPrice, +// ETH_DECIMALS, +// USDC_DECIMALS, +// ); +// expect(JSON.stringify(newSetUnits)).to.be.eql(JSON.stringify(expectedNextSetParams['units'])); +// }); + +// it('updates new stable collateral to the correct components', async () => { +// await subject(); + +// const nextSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// const nextSet = await protocolHelper.getSetTokenAsync(nextSetAddress); +// const nextSetComponents = await nextSet.getComponents.callAsync(); + +// const expectedNextSetComponents = [usdcMock.address]; +// expect(JSON.stringify(nextSetComponents)).to.be.eql(JSON.stringify(expectedNextSetComponents)); +// }); + +// it('updates the auction start price correctly', async () => { +// const txHash = await subject(); + +// const logs = await setTestUtils.getLogsFromTxHash(txHash); +// const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); + +// const baseCollateralValue = await managerHelper.calculateSetTokenValue( +// baseAssetCollateral, +// [triggerPrice], +// [ETH_DECIMALS], +// ); + +// const quoteCollateralValue = await managerHelper.calculateSetTokenValue( +// newSet, +// [ether(1)], +// [USDC_DECIMALS], +// ); + +// const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( +// baseCollateralValue, +// quoteCollateralValue, +// auctionStartPercentage, +// auctionEndPercentage +// ); + +// const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionStartPrice = newAuctionParameters[2]; + +// expect(newAuctionStartPrice).to.be.bignumber.equal(auctionPriceParameters['auctionStartPrice']); +// }); + +// it('updates the auction pivot price correctly', async () => { +// const txHash = await subject(); + +// const logs = await setTestUtils.getLogsFromTxHash(txHash); +// const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); + +// const baseCollateralValue = await managerHelper.calculateSetTokenValue( +// baseAssetCollateral, +// [triggerPrice], +// [ETH_DECIMALS], +// ); + +// const quoteCollateralValue = await managerHelper.calculateSetTokenValue( +// newSet, +// [ether(1)], +// [USDC_DECIMALS], +// ); + +// const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( +// baseCollateralValue, +// quoteCollateralValue, +// auctionStartPercentage, +// auctionEndPercentage +// ); + +// const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionPivotPrice = newAuctionParameters[3]; + +// expect(newAuctionPivotPrice).to.be.bignumber.equal(auctionPriceParameters['auctionPivotPrice']); +// }); +// }); + +// describe('but price has not dipped below MA', async () => { +// before(async () => { +// updateMarketState = false; +// }); + +// after(async () => { +// updateMarketState = true; +// }); + +// it('should revert', async () => { +// await expectRevertError(subject()); +// }); +// }); + +// describe('but not enough time has passed from last rebalance', async () => { +// beforeEach(async () => { +// subjectTimeFastForward = ZERO; +// }); + +// it('should revert', async () => { +// await expectRevertError(subject()); +// }); +// }); +// }); + +// describe('and allocating from quote asset to base asset', async () => { +// before(async () => { +// baseAssetAllocation = ZERO; +// triggerPrice = ether(170); +// }); + +// it('updates to the next set correctly', async () => { +// await subject(); + +// const actualNextSet = await rebalancingSetToken.nextSet.callAsync(); +// expect(actualNextSet).to.equal(baseAssetCollateral.address); +// }); + +// it('updates to the new auction library correctly', async () => { +// await subject(); + +// const newAuctionLibrary = await rebalancingSetToken.auctionLibrary.callAsync(); +// expect(newAuctionLibrary).to.equal(linearAuctionPriceCurve.address); +// }); + +// it('updates the time to pivot correctly', async () => { +// await subject(); + +// const auctionPriceParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionTimeToPivot = auctionPriceParameters[1]; +// expect(newAuctionTimeToPivot).to.be.bignumber.equal(auctionTimeToPivot); +// }); + +// it('updates the auction start price correctly', async () => { +// await subject(); + +// const baseCollateralValue = await managerHelper.calculateSetTokenValue( +// baseAssetCollateral, +// [triggerPrice], +// [ETH_DECIMALS], +// ); + +// const quoteCollateralValue = await managerHelper.calculateSetTokenValue( +// quoteAssetCollateral, +// [ether(1)], +// [USDC_DECIMALS], +// ); + +// const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( +// quoteCollateralValue, +// baseCollateralValue, +// auctionStartPercentage, +// auctionEndPercentage +// ); + +// const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionStartPrice = newAuctionParameters[2]; + +// expect(newAuctionStartPrice).to.be.bignumber.equal(auctionPriceParameters['auctionStartPrice']); +// }); + +// it('updates the auction pivot price correctly', async () => { +// await subject(); + +// const baseCollateralValue = await managerHelper.calculateSetTokenValue( +// baseAssetCollateral, +// [triggerPrice], +// [ETH_DECIMALS], +// ); + +// const quoteCollateralValue = await managerHelper.calculateSetTokenValue( +// quoteAssetCollateral, +// [ether(1)], +// [USDC_DECIMALS], +// ); + +// const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( +// quoteCollateralValue, +// baseCollateralValue, +// auctionStartPercentage, +// auctionEndPercentage +// ); + +// const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionPivotPrice = newAuctionParameters[3]; + +// expect(newAuctionPivotPrice).to.be.bignumber.equal(auctionPriceParameters['auctionPivotPrice']); +// }); + +// describe('but baseAsset collateral is 4x valuable than quoteAsset collateral', async () => { +// before(async () => { +// triggerPrice = ether(400); +// }); + +// it('should pass correct next set address', async () => { +// const txHash = await subject(); + +// const logs = await setTestUtils.getLogsFromTxHash(txHash); +// const expectedNextSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); + +// const actualNextSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// expect(actualNextSetAddress).to.equal(expectedNextSetAddress); +// }); + +// it('updates new risk collateral to the correct naturalUnit', async () => { +// await subject(); + +// const newSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); +// const newSetNaturalUnit = await newSet.naturalUnit.callAsync(); + +// const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( +// quoteAssetCollateral, +// usdcPrice, +// triggerPrice, +// USDC_DECIMALS, +// ETH_DECIMALS, +// ); +// expect(newSetNaturalUnit).to.be.bignumber.equal(expectedNextSetParams['naturalUnit']); +// }); + +// it('updates new risk collateral to the correct units', async () => { +// await subject(); + +// const newSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); +// const newSetUnits = await newSet.getUnits.callAsync(); + +// const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( +// quoteAssetCollateral, +// usdcPrice, +// triggerPrice, +// USDC_DECIMALS, +// ETH_DECIMALS, +// ); +// expect(JSON.stringify(newSetUnits)).to.be.eql(JSON.stringify(expectedNextSetParams['units'])); +// }); + +// it('updates new risk collateral to the correct components', async () => { +// await subject(); + +// const nextSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// const nextSet = await protocolHelper.getSetTokenAsync(nextSetAddress); +// const nextSetComponents = await nextSet.getComponents.callAsync(); + +// const expectedNextSetComponents = [wrappedETH.address]; +// expect(JSON.stringify(nextSetComponents)).to.be.eql(JSON.stringify(expectedNextSetComponents)); +// }); + +// it('updates the auction start price correctly', async () => { +// const txHash = await subject(); + +// const logs = await setTestUtils.getLogsFromTxHash(txHash); +// const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); + +// const baseCollateralValue = await managerHelper.calculateSetTokenValue( +// newSet, +// [triggerPrice], +// [ETH_DECIMALS], +// ); + +// const quoteCollateralValue = await managerHelper.calculateSetTokenValue( +// quoteAssetCollateral, +// [ether(1)], +// [USDC_DECIMALS], +// ); + +// const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( +// quoteCollateralValue, +// baseCollateralValue, +// auctionStartPercentage, +// auctionEndPercentage +// ); + +// const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionStartPrice = newAuctionParameters[2]; + +// expect(newAuctionStartPrice).to.be.bignumber.equal(auctionPriceParameters['auctionStartPrice']); +// }); + +// it('updates the auction pivot price correctly', async () => { +// const txHash = await subject(); + +// const logs = await setTestUtils.getLogsFromTxHash(txHash); +// const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); + +// const baseCollateralValue = await managerHelper.calculateSetTokenValue( +// newSet, +// [triggerPrice], +// [ETH_DECIMALS], +// ); + +// const quoteCollateralValue = await managerHelper.calculateSetTokenValue( +// quoteAssetCollateral, +// [ether(1)], +// [USDC_DECIMALS], +// ); + +// const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( +// quoteCollateralValue, +// baseCollateralValue, +// auctionStartPercentage, +// auctionEndPercentage +// ); + +// const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionPivotPrice = newAuctionParameters[3]; + +// expect(newAuctionPivotPrice).to.be.bignumber.equal(auctionPriceParameters['auctionPivotPrice']); +// }); +// }); + +// describe('but new risk collateral requires bump in natural unit', async () => { +// before(async () => { +// triggerPrice = ether(3 * 10 ** 8); +// }); + +// it('should pass correct next set address', async () => { +// const txHash = await subject(); + +// const logs = await setTestUtils.getLogsFromTxHash(txHash); +// const expectedNextSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); + +// const actualNextSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// expect(actualNextSetAddress).to.equal(expectedNextSetAddress); +// }); + +// it('updates new risk collateral to the correct naturalUnit', async () => { +// await subject(); + +// const newSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); +// const newSetNaturalUnit = await newSet.naturalUnit.callAsync(); + +// const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( +// quoteAssetCollateral, +// usdcPrice, +// triggerPrice, +// USDC_DECIMALS, +// ETH_DECIMALS, +// ); + +// expect(newSetNaturalUnit).to.be.bignumber.equal(expectedNextSetParams['naturalUnit']); +// }); + +// it('updates new risk collateral to the correct units', async () => { +// await subject(); + +// const newSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); +// const newSetUnits = await newSet.getUnits.callAsync(); + +// const expectedNextSetParams = await managerHelper.getExpectedNewBinaryAllocationParametersAsync( +// quoteAssetCollateral, +// usdcPrice, +// triggerPrice, +// USDC_DECIMALS, +// ETH_DECIMALS, +// ); +// expect(JSON.stringify(newSetUnits)).to.be.eql(JSON.stringify(expectedNextSetParams['units'])); +// }); + +// it('updates new risk collateral to the correct components', async () => { +// await subject(); + +// const nextSetAddress = await rebalancingSetToken.nextSet.callAsync(); +// const nextSet = await protocolHelper.getSetTokenAsync(nextSetAddress); +// const nextSetComponents = await nextSet.getComponents.callAsync(); + +// const expectedNextSetComponents = [wrappedETH.address]; +// expect(JSON.stringify(nextSetComponents)).to.be.eql(JSON.stringify(expectedNextSetComponents)); +// }); + +// it('updates the auction start price correctly', async () => { +// const txHash = await subject(); + +// const logs = await setTestUtils.getLogsFromTxHash(txHash); +// const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); + +// const baseCollateralValue = await managerHelper.calculateSetTokenValue( +// newSet, +// [triggerPrice], +// [ETH_DECIMALS], +// ); + +// const quoteCollateralValue = await managerHelper.calculateSetTokenValue( +// quoteAssetCollateral, +// [ether(1)], +// [USDC_DECIMALS], +// ); + +// const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( +// quoteCollateralValue, +// baseCollateralValue, +// auctionStartPercentage, +// auctionEndPercentage +// ); + +// const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionStartPrice = newAuctionParameters[2]; + +// expect(newAuctionStartPrice).to.be.bignumber.equal(auctionPriceParameters['auctionStartPrice']); +// }); + +// it('updates the auction pivot price correctly', async () => { +// const txHash = await subject(); + +// const logs = await setTestUtils.getLogsFromTxHash(txHash); +// const newSetAddress = extractNewSetTokenAddressFromLogs([logs[0]]); +// const newSet = await protocolHelper.getSetTokenAsync(newSetAddress); + +// const baseCollateralValue = await managerHelper.calculateSetTokenValue( +// newSet, +// [triggerPrice], +// [ETH_DECIMALS], +// ); + +// const quoteCollateralValue = await managerHelper.calculateSetTokenValue( +// quoteAssetCollateral, +// [ether(1)], +// [USDC_DECIMALS], +// ); + +// const auctionPriceParameters = managerHelper.calculateLinearAuctionParameters( +// quoteCollateralValue, +// baseCollateralValue, +// auctionStartPercentage, +// auctionEndPercentage +// ); + +// const newAuctionParameters = await rebalancingSetToken.auctionPriceParameters.callAsync(); +// const newAuctionPivotPrice = newAuctionParameters[3]; + +// expect(newAuctionPivotPrice).to.be.bignumber.equal(auctionPriceParameters['auctionPivotPrice']); +// }); +// }); + +// describe('but price has not gone above MA', async () => { +// before(async () => { +// updateMarketState = false; +// }); + +// after(async () => { +// updateMarketState = true; +// }); + +// it('should revert', async () => { +// await expectRevertError(subject()); +// }); +// }); + +// describe('but not enough time has passed from last rebalance', async () => { +// beforeEach(async () => { +// subjectTimeFastForward = ZERO; +// }); + +// it('should revert', async () => { +// await expectRevertError(subject()); +// }); +// }); +// }); +// }); + +// describe('when propose is called and rebalancing set token is in Proposal state', async () => { +// beforeEach(async () => { +// await blockchain.increaseTimeAsync(subjectTimeFastForward); +// await setManager.propose.sendTransactionAsync(); +// }); + +// it('should revert', async () => { +// await expectRevertError(subject()); +// }); +// }); + +// describe('when propose is called and rebalancing set token is in Rebalance state', async () => { +// beforeEach(async () => { +// // Issue currentSetToken +// const initialAllocationTokenAddress = await rebalancingSetToken.currentSet.callAsync(); +// const initialAllocationToken = await protocolHelper.getSetTokenAsync(initialAllocationTokenAddress); +// await core.issue.sendTransactionAsync( +// initialAllocationToken.address, +// ether(9), +// {from: deployerAccount, gas: DEFAULT_GAS}, +// ); +// await erc20Helper.approveTransfersAsync([initialAllocationToken], transferProxy.address); + +// // Use issued currentSetToken to issue rebalancingSetToken +// await core.issue.sendTransactionAsync( +// rebalancingSetToken.address, +// ether(7), +// { from: deployerAccount, gas: DEFAULT_GAS } +// ); + +// await blockchain.increaseTimeAsync(subjectTimeFastForward); +// await setManager.propose.sendTransactionAsync(); + +// await blockchain.increaseTimeAsync(ONE_DAY_IN_SECONDS); +// await rebalancingSetToken.startRebalance.sendTransactionAsync(); +// }); + +// it('should revert', async () => { +// await expectRevertError(subject()); +// }); +// }); +// }); +// }); \ No newline at end of file diff --git a/utils/contract_logs/iTrigger.ts b/utils/contract_logs/iTrigger.ts deleted file mode 100644 index 62dc89e..0000000 --- a/utils/contract_logs/iTrigger.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { BigNumber } from 'bignumber.js'; -import { Address, Log } from 'set-protocol-utils'; - -export function LogTriggerFlipped( - _flipTo: boolean, - _triggerFlippedIndex: BigNumber, - _timestamp: BigNumber, - _contractAddress: Address, -): Log[] { - return [{ - event: 'TriggerFlipped', - address: _contractAddress, - args: { - _flipTo, - _triggerFlippedIndex, - _timestamp, - }, - }]; -} \ No newline at end of file diff --git a/utils/contracts.ts b/utils/contracts.ts index 3281d18..2cf2a29 100644 --- a/utils/contracts.ts +++ b/utils/contracts.ts @@ -28,9 +28,7 @@ export { ManagerLibraryMockContract } from '../types/generated/manager_library_m export { MovingAverageOracleContract } from '../types/generated/moving_average_oracle'; export { MovingAverageOracleV2Contract } from '../types/generated/moving_average_oracle_v2'; export { MovingAverageOracleV1ProxyContract } from '../types/generated/moving_average_oracle_v1_proxy'; -export { - MovingAverageToAssetPriceCrossoverTriggerContract -} from '../types/generated/moving_average_to_asset_price_crossover_trigger'; +export { MovingAverageCrossoverTriggerContract } from '../types/generated/moving_average_crossover_trigger'; export { OracleProxyCallerContract } from '../types/generated/oracle_proxy_caller'; export { OracleProxyContract } from '../types/generated/oracle_proxy'; export { PriceFeedContract } from '../types/generated/price_feed'; diff --git a/utils/helpers/managerHelper.ts b/utils/helpers/managerHelper.ts index 40e7366..7f6bdcc 100644 --- a/utils/helpers/managerHelper.ts +++ b/utils/helpers/managerHelper.ts @@ -17,7 +17,7 @@ import { MACOStrategyManagerV2Contract, MovingAverageOracleContract, MovingAverageOracleV2Contract, - MovingAverageToAssetPriceCrossoverTriggerContract, + MovingAverageCrossoverTriggerContract, RSITrendingTriggerContract, TriggerMockContract, TriggerIndexManagerContract, @@ -49,8 +49,8 @@ const ETHDaiRebalancingManager = artifacts.require('ETHDaiRebalancingManager'); const InverseMACOStrategyManager = artifacts.require('InverseMACOStrategyManager'); const MACOStrategyManager = artifacts.require('MACOStrategyManager'); const MACOStrategyManagerV2 = artifacts.require('MACOStrategyManagerV2'); -const MovingAverageToAssetPriceCrossoverTrigger = artifacts.require( - 'MovingAverageToAssetPriceCrossoverTrigger' +const MovingAverageCrossoverTrigger = artifacts.require( + 'MovingAverageCrossoverTrigger' ); const RSITrendingTrigger = artifacts.require('RSITrendingTrigger'); const TriggerMock = artifacts.require('TriggerMock'); @@ -368,26 +368,20 @@ export class ManagerHelper { } - public async deployMovingAverageToAssetPriceCrossoverTrigger( + public async deployMovingAverageCrossoverTrigger( movingAveragePriceFeed: Address, assetPairOracle: Address, movingAverageDays: BigNumber, - initialState: boolean, - signalConfirmationMinTime: BigNumber, - signalConfirmationMaxTime: BigNumber, from: Address = this._tokenOwnerAddress, - ): Promise { - const trufflePriceTrigger = await MovingAverageToAssetPriceCrossoverTrigger.new( + ): Promise { + const trufflePriceTrigger = await MovingAverageCrossoverTrigger.new( movingAveragePriceFeed, assetPairOracle, movingAverageDays, - signalConfirmationMinTime, - signalConfirmationMaxTime, - initialState, { from } ); - return new MovingAverageToAssetPriceCrossoverTriggerContract( + return new MovingAverageCrossoverTriggerContract( new web3.eth.Contract(trufflePriceTrigger.abi, trufflePriceTrigger.address), { from, gas: DEFAULT_GAS }, ); @@ -398,7 +392,6 @@ export class ManagerHelper { lowerBound: BigNumber, upperBound: BigNumber, rsiTimePeriod: BigNumber, - initialTrendState: boolean, from: Address = this._tokenOwnerAddress, ): Promise { const trufflePriceTrigger = await RSITrendingTrigger.new( @@ -406,7 +399,6 @@ export class ManagerHelper { lowerBound, upperBound, rsiTimePeriod, - initialTrendState, { from } ); From 7b97f0d12ae4ec76f6248db4eafa4af3a2cf626b Mon Sep 17 00:00:00 2001 From: felix2feng Date: Mon, 4 Nov 2019 19:42:50 -0800 Subject: [PATCH 2/2] FIx lint --- .../managers/triggers/movingAverageCrossoverTrigger.spec.ts | 2 ++ test/contracts/managers/triggers/rsiTrendingTrigger.spec.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/test/contracts/managers/triggers/movingAverageCrossoverTrigger.spec.ts b/test/contracts/managers/triggers/movingAverageCrossoverTrigger.spec.ts index b091045..6738bc3 100644 --- a/test/contracts/managers/triggers/movingAverageCrossoverTrigger.spec.ts +++ b/test/contracts/managers/triggers/movingAverageCrossoverTrigger.spec.ts @@ -3,6 +3,7 @@ require('module-alias/register'); import * as _ from 'lodash'; import * as ABIDecoder from 'abi-decoder'; import * as chai from 'chai'; +import * as setProtocolUtils from 'set-protocol-utils'; import { Address } from 'set-protocol-utils'; import { BigNumber } from 'bignumber.js'; @@ -43,6 +44,7 @@ const MovingAverageCrossoverTrigger = artifacts.require('MovingAverageCrossoverT const web3 = getWeb3(); const { expect } = chai; const blockchain = new Blockchain(web3); +const { SetProtocolTestUtils: SetTestUtils } = setProtocolUtils; contract('MovingAverageCrossoverTrigger', accounts => { const [ diff --git a/test/contracts/managers/triggers/rsiTrendingTrigger.spec.ts b/test/contracts/managers/triggers/rsiTrendingTrigger.spec.ts index 36035cf..c1e4f8d 100644 --- a/test/contracts/managers/triggers/rsiTrendingTrigger.spec.ts +++ b/test/contracts/managers/triggers/rsiTrendingTrigger.spec.ts @@ -3,6 +3,7 @@ require('module-alias/register'); import * as _ from 'lodash'; import * as ABIDecoder from 'abi-decoder'; import * as chai from 'chai'; +import * as setProtocolUtils from 'set-protocol-utils'; import { Address } from 'set-protocol-utils'; import { BigNumber } from 'bignumber.js'; @@ -44,6 +45,7 @@ const RSITrendingTrigger = artifacts.require('RSITrendingTrigger'); const web3 = getWeb3(); const { expect } = chai; const blockchain = new Blockchain(web3); +const { SetProtocolTestUtils: SetTestUtils } = setProtocolUtils; contract('RSITrendingTrigger', accounts => { const [