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
2 changes: 2 additions & 0 deletions artifacts/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { ChainlinkOracleAdapter } from './ts/ChainlinkOracleAdapter';
export { ConstantPriceOracle } from './ts/ConstantPriceOracle';
export { CTokenOracle } from './ts/CTokenOracle';
export { DydxOracleAdapter } from './ts/DydxOracleAdapter';
Expand All @@ -24,6 +25,7 @@ export { UpdatableOracleMock } from './ts/UpdatableOracleMock';
// Export abi-gen contract wrappers
export {
BaseContract,
ChainlinkOracleAdapterContract,
ConstantPriceOracleContract,
CTokenOracleContract,
DydxOracleAdapterContract,
Expand Down
70 changes: 70 additions & 0 deletions contracts/meta-oracles/proxies/ChainlinkOracleAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
Copyright 2020 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;

import { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol";
import { AggregatorInterface } from "chainlink/v0.5/contracts/dev/AggregatorInterface.sol";


/**
* @title ChainlinkOracleAdapter
* @author Set Protocol
*
* Coerces outputs from Chainlink oracles to uint256 and adapts value to 18 decimals.
*/
contract ChainlinkOracleAdapter {
using SafeMath for uint256;

/* ============ Constants ============ */
uint256 public constant PRICE_MULTIPLIER = 1e10;

/* ============ State Variables ============ */
AggregatorInterface public oracle;

/* ============ Constructor ============ */
/*
* Set address of aggregator being adapted for use
*
* @param _oracle The address of medianizer being adapted from bytes to uint256
*/
constructor(
AggregatorInterface _oracle
)
public
{
oracle = _oracle;
}

/* ============ External ============ */

/*
* Reads value of oracle and coerces return to uint256 then applies price multiplier
*
* @returns Chainlink oracle price in uint256
*/
function read()
external
view
returns (uint256)
{
// Read value of medianizer and coerce to uint256
uint256 oracleOutput = uint256(oracle.latestAnswer());

// Apply multiplier to create 18 decimal price (since Chainlink returns 8 decimals)
return oracleOutput.mul(PRICE_MULTIPLIER);
}
}
15 changes: 15 additions & 0 deletions contracts/mocks/ChainlinkAggregatorMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
pragma solidity 0.5.7;

contract ChainlinkAggregatorMock {
int256 public latestAnswer;
uint256 public latestTimestamp;

constructor(int256 _latestAnswer) public {
setLatestAnswer(_latestAnswer);
}

function setLatestAnswer(int256 _latestAnswer) public {
latestAnswer = _latestAnswer;
latestTimestamp = now;
}
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "set-protocol-oracles",
"version": "1.0.1",
"version": "1.0.2",
"main": "dist/artifacts/index.js",
"typings": "dist/typings/artifacts/index.d.ts",
"files": [
Expand Down Expand Up @@ -91,6 +91,7 @@
"dependencies": {
"bn-chai": "^1.0.1",
"canonical-weth": "^1.3.1",
"chainlink": "^0.7.10",
"dotenv": "^6.2.0",
"eth-gas-reporter": "^0.1.10",
"ethlint": "^1.2.3",
Expand Down
96 changes: 96 additions & 0 deletions test/contracts/oracles/proxies/chainlinkOracleAdapter.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
require('module-alias/register');

import * as _ from 'lodash';
import * as chai from 'chai';

import { Address } from 'set-protocol-utils';
import { BigNumber } from 'bignumber.js';
import { ether } from '@utils/units';

import ChaiSetup from '@utils/chaiSetup';
import { BigNumberSetup } from '@utils/bigNumberSetup';
import { Blockchain } from '@utils/blockchain';

import {
ChainlinkAggregatorMockContract,
ChainlinkOracleAdapterContract,
} from '@utils/contracts';

import { getWeb3 } from '@utils/web3Helper';

import { OracleHelper } from '@utils/helpers/oracleHelper';

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

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

let customDollarValue: number;
let customOracleValue: BigNumber;
let chainlinkAggregatorMock: ChainlinkAggregatorMockContract;

let chainlinkOracleAdapter: ChainlinkOracleAdapterContract;


const oracleHelper = new OracleHelper(deployerAccount);

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

customDollarValue = 100;
// Equal to 100 since Chainlink numbers are 8 decimal
customOracleValue = new BigNumber(10 ** 8).mul(customDollarValue);
chainlinkAggregatorMock = await oracleHelper.deployChainlinkAggregatorMockAsync(
customOracleValue
);
});

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

describe('#constructor', async () => {
let subjectChainlinkOracleAddress: Address;

beforeEach(async () => {
subjectChainlinkOracleAddress = chainlinkAggregatorMock.address;
});

async function subject(): Promise<ChainlinkOracleAdapterContract> {
return oracleHelper.deployChainlinkOracleAdapterAsync(
subjectChainlinkOracleAddress,
);
}

it('sets the correct Chainlink Oracle Address', async () => {
chainlinkOracleAdapter = await subject();

const actualChainlinkOracleAddress = await chainlinkOracleAdapter.oracle.callAsync();

expect(actualChainlinkOracleAddress).to.be.bignumber.equal(subjectChainlinkOracleAddress);
});
});

describe('#read', async () => {
beforeEach(async () => {
chainlinkOracleAdapter = await oracleHelper.deployChainlinkOracleAdapterAsync(
chainlinkAggregatorMock.address,
);
});

async function subject(): Promise<BigNumber> {
return chainlinkOracleAdapter.read.callAsync();
}

it('returns the correct price in uint256', async () => {
const actualTokenPrice = await subject();
expect(actualTokenPrice).to.be.bignumber.equal(ether(customDollarValue));
});
});
});
6 changes: 4 additions & 2 deletions utils/contracts.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
export { BaseContract } from '../types/base_contract';
export { ChainlinkAggregatorMockContract } from '../types/generated/chainlink_aggregator_mock';
export { ChainlinkOracleAdapterContract } from '../types/generated/chainlink_oracle_adapter';
export { ConstantPriceOracleContract } from '../types/generated/constant_price_oracle';
export { CTokenOracleContract } from '../types/generated/c_token_oracle';
export {
DataSourceLinearInterpolationLibraryMockContract
} from '../types/generated/data_source_linear_interpolation_library_mock';
export { ConstantPriceOracleContract } from '../types/generated/constant_price_oracle';
export { CTokenOracleContract } from '../types/generated/c_token_oracle';
export { DydxConstantPriceOracleMockContract } from '../types/generated/dydx_constant_price_oracle_mock';
export { DydxOracleAdapterContract } from '../types/generated/dydx_oracle_adapter';
export { EMALibraryMockContract } from '../types/generated/e_m_a_library_mock';
Expand Down
34 changes: 34 additions & 0 deletions utils/helpers/oracleHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { Blockchain } from '@utils/blockchain';
import { ether } from '@utils/units';

import {
ChainlinkAggregatorMockContract,
ChainlinkOracleAdapterContract,
ConstantPriceOracleContract,
CTokenOracleContract,
DydxConstantPriceOracleMockContract,
Expand Down Expand Up @@ -41,6 +43,8 @@ import { FeedCreatedArgs } from '../contract_logs/oracle';

const web3 = getWeb3();

const ChainlinkAggregatorMock = artifacts.require('ChainlinkAggregatorMock');
const ChainlinkOracleAdapter = artifacts.require('ChainlinkOracleAdapter');
const ConstantPriceOracle = artifacts.require('ConstantPriceOracle');
const CTokenOracle = artifacts.require('CTokenOracle');
const DydxConstantPriceOracleMock = artifacts.require('DydxConstantPriceOracleMock');
Expand Down Expand Up @@ -481,6 +485,36 @@ export class OracleHelper {
);
}

public async deployChainlinkOracleAdapterAsync(
oracle: Address,
from: Address = this._contractOwnerAddress
): Promise<ChainlinkOracleAdapterContract> {
const oracleAdapter = await ChainlinkOracleAdapter.new(
oracle,
txnFrom(from),
);

return new ChainlinkOracleAdapterContract(
getContractInstance(oracleAdapter),
txnFrom(from),
);
}

public async deployChainlinkAggregatorMockAsync(
oracleValue: BigNumber,
from: Address = this._contractOwnerAddress
): Promise<ChainlinkAggregatorMockContract> {
const oracleAMock = await ChainlinkAggregatorMock.new(
oracleValue,
txnFrom(from),
);

return new ChainlinkAggregatorMockContract(
getContractInstance(oracleAMock),
txnFrom(from),
);
}

/* ============ Transactions ============ */

public async addPriceFeedOwnerToMedianizer(
Expand Down
Loading