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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions contracts/meta-oracles/LinearizedPriceDataSource.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { TimeLockUpgrade } from "set-protocol-contracts/contracts/lib/TimeLockUp
import { DataSourceLinearInterpolationLibrary } from "./lib/DataSourceLinearInterpolationLibrary.sol";
import { IOracle } from "./interfaces/IOracle.sol";
import { IDataSource } from "./interfaces/IDataSource.sol";
import { LinkedListHelper } from "./lib/LinkedListHelper.sol";
import { LinkedListLibraryV2 } from "./lib/LinkedListLibraryV2.sol";
import { TimeSeriesStateLibrary } from "./lib/TimeSeriesStateLibrary.sol";


Expand All @@ -39,6 +41,7 @@ contract LinearizedPriceDataSource is
IDataSource
{
using SafeMath for uint256;
using LinkedListHelper for LinkedListLibraryV2.LinkedList;

/* ============ State Variables ============ */
// Amount of time after which read interpolates price result, in seconds
Expand Down Expand Up @@ -91,9 +94,9 @@ contract LinearizedPriceDataSource is
* @returns Returns the datapoint from the oracle contract
*/
function read(
TimeSeriesStateLibrary.State calldata _timeSeriesState
TimeSeriesStateLibrary.State memory _timeSeriesState
)
external
public
view
returns (uint256)
{
Expand All @@ -114,11 +117,13 @@ contract LinearizedPriceDataSource is
if (timeFromExpectedUpdate < interpolationThreshold) {
return oracleValue;
} else {
uint256 mostRecentPrice = _timeSeriesState.timeSeriesData.getLatestValue();

return DataSourceLinearInterpolationLibrary.interpolateDelayedPriceUpdate(
oracleValue,
_timeSeriesState.updateInterval,
timeFromExpectedUpdate,
_timeSeriesState.timeSeriesDataArray[0]
mostRecentPrice
);
}
}
Expand Down
10 changes: 2 additions & 8 deletions contracts/meta-oracles/TimeSeriesFeed.sol
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ contract TimeSeriesFeed is

/*
* Generate struct that holds TimeSeriesFeed's current nextAvailableUpdate, updateInterval,
* and previously logged prices.
* and the LinkedList struct
*
* @returns Struct containing the above params
*/
Expand All @@ -157,16 +157,10 @@ contract TimeSeriesFeed is
view
returns (TimeSeriesStateLibrary.State memory)
{
// Get timeSeriesData price values from most recent to oldest
uint256[] memory timeSeriesDataArray = timeSeriesData.readList(
timeSeriesData.dataArray.length
);

return TimeSeriesStateLibrary.State({
nextEarliestUpdate: nextEarliestUpdate,
updateInterval: updateInterval,
timeSeriesDataArray: timeSeriesDataArray
timeSeriesData: timeSeriesData
});

}
}
44 changes: 44 additions & 0 deletions contracts/meta-oracles/lib/LinkedListHelper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
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 { LinkedListLibraryV2 } from "./LinkedListLibraryV2.sol";


/**
* @title LinkedListHelper
* @author Set Protocol
*
* Convenience methods for the LinkedListLibrary
*/
library LinkedListHelper {
using LinkedListLibraryV2 for LinkedListLibraryV2.LinkedList;

/* ============ Structs ============ */

function getLatestValue(
LinkedListLibraryV2.LinkedList memory _self
)
internal
view
returns (uint256)
{
uint256[] memory currentTimeSeriesValues = _self.readListMemory(1);
return currentTimeSeriesValues[0];
}
}
17 changes: 17 additions & 0 deletions contracts/meta-oracles/lib/LinkedListLibraryV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,22 @@ library LinkedListLibraryV2 {
internal
view
returns (uint256[] memory)
{
LinkedList memory linkedListMemory = _self;

return readListMemory(
linkedListMemory,
_dataPoints
);
}

function readListMemory(
LinkedList memory _self,
uint256 _dataPoints
)
internal
view
returns (uint256[] memory)
{
// Make sure query isn't for more data than collected
require(
Expand All @@ -180,4 +196,5 @@ library LinkedListLibraryV2 {

return outputArray;
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Remove extra space

}
3 changes: 2 additions & 1 deletion contracts/meta-oracles/lib/TimeSeriesStateLibrary.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

pragma solidity 0.5.7;
pragma experimental "ABIEncoderV2";
import { LinkedListLibraryV2 } from "./LinkedListLibraryV2.sol";

Copy link
Contributor

Choose a reason for hiding this comment

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

Remove extra space


/**
Expand All @@ -28,6 +29,6 @@ library TimeSeriesStateLibrary {
struct State {
uint256 nextEarliestUpdate;
uint256 updateInterval;
uint256[] timeSeriesDataArray;
LinkedListLibraryV2.LinkedList timeSeriesData;
}
}
42 changes: 42 additions & 0 deletions contracts/mocks/meta-oracles/lib/LinkedListHelperMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
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 { LinkedListLibraryV2 } from "../../../meta-oracles/lib/LinkedListLibraryV2.sol";
import { LinkedListHelper } from "../../../meta-oracles/lib/LinkedListHelper.sol";

/**
* @title LinkedListHelperMock
* @author Set Protocol
*
* Convenience methods for the LinkedListLibrary
*/
contract LinkedListHelperMock {

/* ============ Public Function ============ */

function getLatestValueMock(
LinkedListLibraryV2.LinkedList memory _self
)
public
view
returns (uint256)
{
return LinkedListHelper.getLatestValue(_self);
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
"module-alias": "^2.1.0",
"openzeppelin-solidity": "^2.2",
"set-protocol-contracts": "^1.2.3",
"set-protocol-utils": "^1.0.0-beta.38",
"set-protocol-utils": "^1.0.0-beta.39",
"tiny-promisify": "^1.0.0",
"truffle-flattener": "^1.4.0",
"ts-mocha": "^6.0.0",
Expand Down
85 changes: 85 additions & 0 deletions test/contracts/meta-oracles/lib/linkedListHelperMock.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
require('module-alias/register');

import * as _ from 'lodash';
import * as chai from 'chai';
import { BigNumber } from 'bignumber.js';

import ChaiSetup from '@utils/chaiSetup';
import { BigNumberSetup } from '@utils/bigNumberSetup';
import {
LinkedListHelperMockContract,
} from '@utils/contracts';
import { Blockchain } from '@utils/blockchain';
import { ether } from '@utils/units';
import {
DEFAULT_GAS
} from '@utils/constants';
import { getWeb3 } from '@utils/web3Helper';

import { LibraryMockWrapper } from '@utils/wrappers/libraryMockWrapper';

BigNumberSetup.configure();
ChaiSetup.configure();
const web3 = getWeb3();
const { expect } = chai;
const blockchain = new Blockchain(web3);

contract('LinkedListHelper', accounts => {
const [
deployerAccount,
] = accounts;

let linkedListLibraryMock: LinkedListHelperMockContract;

const libraryMockWrapper = new LibraryMockWrapper(deployerAccount);

beforeEach(async () => {
blockchain.saveSnapshotAsync();

linkedListLibraryMock = await libraryMockWrapper.deployLinkedListHelperMockAsync();
});

afterEach(async () => {
blockchain.revertAsync();
});

describe('#getLatestValue', async () => {
let lastUpdatedIndex: BigNumber;
let dataArray: BigNumber[];
let dataSizeLimit: BigNumber;

let subjectLinkedList: any;

beforeEach(async () => {
lastUpdatedIndex = new BigNumber(4);
dataSizeLimit = new BigNumber(5);

dataArray = [
ether(160),
ether(175),
ether(157),
ether(162),
ether(173),
];

subjectLinkedList = {
dataSizeLimit,
lastUpdatedIndex,
dataArray,
};
});

async function subject(): Promise<BigNumber> {
return linkedListLibraryMock.getLatestValueMock.callAsync(
subjectLinkedList,
{ gas: DEFAULT_GAS }
);
}

it('gets the correct last value', async () => {
const latestValue = await subject();

expect(latestValue).to.bignumber.equal(dataArray[lastUpdatedIndex.toNumber()]);
});
});
});
12 changes: 8 additions & 4 deletions test/contracts/meta-oracles/linearizedPriceDataSource.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,17 @@ contract('LinearizedPriceDataSource', accounts => {

const nextEarliestUpdate = new BigNumber(block.timestamp);
const updateInterval = ONE_DAY_IN_SECONDS;
const timeSeriesDataArray = [ether(100)];

subjectTimeSeriesState = {
nextEarliestUpdate,
updateInterval,
timeSeriesDataArray,
timeSeriesData: {
dataSizeLimit: new BigNumber(5),
lastUpdatedIndex: new BigNumber(0),
dataArray: [ether(100)],
},
} as TimeSeriesFeedState;

subjectTimeFastForward = ZERO;
});

Expand Down Expand Up @@ -201,7 +205,7 @@ contract('LinearizedPriceDataSource', accounts => {
const timeFromExpectedUpdate = new BigNumber(block.timestamp).sub(subjectTimeSeriesState.nextEarliestUpdate);

const timeFromLastUpdate = timeFromExpectedUpdate.add(subjectTimeSeriesState.updateInterval);
const previousLoggedPrice = subjectTimeSeriesState.timeSeriesDataArray[0];
const previousLoggedPrice = subjectTimeSeriesState.timeSeriesData.dataArray[0];
const expectedNewPrice = newEthPrice
.mul(subjectTimeSeriesState.updateInterval)
.add(previousLoggedPrice.mul(timeFromExpectedUpdate))
Expand Down Expand Up @@ -232,7 +236,7 @@ contract('LinearizedPriceDataSource', accounts => {
const timeFromExpectedUpdate = new BigNumber(block.timestamp).sub(subjectTimeSeriesState.nextEarliestUpdate);

const timeFromLastUpdate = timeFromExpectedUpdate.add(subjectTimeSeriesState.updateInterval);
const previousLoggedPrice = subjectTimeSeriesState.timeSeriesDataArray[0];
const previousLoggedPrice = subjectTimeSeriesState.timeSeriesData.dataArray[0];
const expectedNewPrice = newEthPrice
.mul(subjectTimeSeriesState.updateInterval)
.add(previousLoggedPrice.mul(timeFromExpectedUpdate))
Expand Down
28 changes: 9 additions & 19 deletions test/contracts/meta-oracles/timeSeriesFeed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ contract('TimeSeriesFeed', accounts => {

describe('#getTimeSeriesFeedState', async () => {
let ethPrice: BigNumber;
let numberOfUpdates: number = undefined;
const numberOfUpdates: number = 20;

let maxDataPoints: BigNumber;
let updateInterval: BigNumber;
Expand All @@ -355,7 +355,7 @@ contract('TimeSeriesFeed', accounts => {
updatedPrices = await oracleWrapper.batchUpdateTimeSeriesFeedAsync(
timeSeriesFeed,
ethMedianizer,
numberOfUpdates || 20,
numberOfUpdates,
);
});

Expand All @@ -366,27 +366,17 @@ contract('TimeSeriesFeed', accounts => {
it('returns the correct TimeSeriesState struct', async () => {
const timeSeriesState = await subject();

const expectedDailyPriceOutput = updatedPrices.reverse();
expectedDailyPriceOutput.push(ethPrice);
const [actualNextEarliestUpdate, actualUpdateInterval, timeSeriesData] = timeSeriesState;

const expectedNextEarliestUpdate = await timeSeriesFeed.nextEarliestUpdate.callAsync();

expect(timeSeriesState.nextEarliestUpdate).to.be.bignumber.equal(expectedNextEarliestUpdate);
expect(timeSeriesState.updateInterval).to.be.bignumber.equal(updateInterval);
expect(JSON.stringify(timeSeriesState.timeSeriesDataArray)).to.equal(JSON.stringify(expectedDailyPriceOutput));
});

describe('when more than maxDataPoints has been passed', async () => {
before(async () => {
numberOfUpdates = 205;
});
const expectedDataArray = [ethPrice].concat(updatedPrices);

it('should returns last maxDataPoints values in order', async () => {
const timeSeriesState = await subject();

const expectedDailyPriceOutput = updatedPrices.slice(-maxDataPoints.toNumber()).reverse();
expect(JSON.stringify(timeSeriesState.timeSeriesDataArray)).to.equal(JSON.stringify(expectedDailyPriceOutput));
});
expect(actualNextEarliestUpdate).to.be.bignumber.equal(expectedNextEarliestUpdate);
expect(actualUpdateInterval).to.be.bignumber.equal(updateInterval);
expect(JSON.stringify(timeSeriesData.dataArray)).to.equal(JSON.stringify(expectedDataArray));
expect(timeSeriesData.lastUpdatedIndex).to.bignumber.equal(numberOfUpdates);
expect(timeSeriesData.dataSizeLimit).to.bignumber.equal(maxDataPoints);
});
});
});
Loading