Skip to content

Commit 7a6f9ab

Browse files
committed
Initial commit with contracts and boilerplate files
1 parent 8c1bdb6 commit 7a6f9ab

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+11324
-1
lines changed

.changeset/config.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
3+
"changelog": "@changesets/cli/changelog",
4+
"commit": false,
5+
"fixed": [],
6+
"linked": [],
7+
"access": "public",
8+
"baseBranch": "main",
9+
"updateInternalDependencies": "patch",
10+
"ignore": []
11+
}

.eslintignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
node_modules
2+
.env
3+
dist
4+
5+
# Hardhat files
6+
/cache
7+
/artifacts
8+
9+
# TypeChain files
10+
/typechain
11+
/typechain-types
12+
13+
# solidity-coverage files
14+
/coverage
15+
/coverage.json
16+
17+
gas_report
18+
19+
contracts/vendor

.eslintrc.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module.exports = {
2+
extends: ['plugin:@api3/eslint-plugin-commons/universal', 'plugin:@api3/eslint-plugin-commons/jest'],
3+
parserOptions: {
4+
project: ['./tsconfig.json'],
5+
},
6+
rules: {
7+
camelcase: 'off',
8+
'no-nested-ternary': 'off',
9+
10+
'functional/no-try-statements': 'off',
11+
12+
'jest/no-conditional-in-test': 'off',
13+
14+
'lodash/prefer-constant': 'off',
15+
'lodash/prefer-lodash-typecheck': 'off',
16+
'lodash/prefer-noop': 'off',
17+
18+
'unicorn/filename-case': 'off',
19+
'unicorn/no-anonymous-default-export': 'off',
20+
'unicorn/prefer-export-from': 'off',
21+
'unicorn/prefer-object-from-entries': 'off',
22+
'unicorn/prefer-ternary': 'off',
23+
24+
'@typescript-eslint/max-params': 'off',
25+
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
26+
'@typescript-eslint/no-unsafe-call': 'off',
27+
'@typescript-eslint/require-await': 'off',
28+
},
29+
};

.github/workflows/check-md-links.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: Check Markdown links
2+
3+
on: push
4+
5+
jobs:
6+
check-md-links:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- name: Clone @api3/data-feed-proxy-combinators
10+
uses: actions/checkout@v4
11+
- name: Check Markdown links
12+
uses: gaurav-nelson/github-action-markdown-link-check@v1
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Continuous build
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
lint-build-test:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Clone @api3/data-feed-proxy-combinators
16+
uses: actions/checkout@v4
17+
18+
- name: Set up pnpm
19+
uses: pnpm/action-setup@v3
20+
21+
- name: Set up Node
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: '20.17.0'
25+
cache: 'pnpm'
26+
27+
- name: Install dependencies
28+
run: pnpm install
29+
30+
- name: Lint
31+
run: pnpm lint
32+
33+
- name: Build
34+
run: pnpm build
35+
36+
- name: Verify vendor contracts
37+
run: pnpm verify-vendor-contracts
38+
39+
- name: Test
40+
run: pnpm test

.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
node_modules
2+
.env
3+
dist
4+
5+
# Hardhat files
6+
/cache
7+
/artifacts
8+
9+
# TypeChain files
10+
/typechain
11+
/typechain-types
12+
13+
# solidity-coverage files
14+
/coverage
15+
/coverage.json
16+
17+
gas_report

.prettierignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
node_modules
2+
.env
3+
dist
4+
5+
# Hardhat files
6+
/cache
7+
/artifacts
8+
9+
# TypeChain files
10+
/typechain
11+
/typechain-types
12+
13+
# solidity-coverage files
14+
/coverage
15+
/coverage.json
16+
17+
gas_report
18+
19+
contracts/vendor

.prettierrc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"bracketSpacing": true,
3+
"printWidth": 120,
4+
"singleQuote": true,
5+
"trailingComma": "es5",
6+
"useTabs": false,
7+
"plugins": ["prettier-plugin-solidity"],
8+
"overrides": [
9+
{
10+
"files": "*.md",
11+
"options": {
12+
"parser": "markdown"
13+
}
14+
},
15+
{
16+
"files": "*.sol",
17+
"options": {
18+
"parser": "antlr",
19+
"printWidth": 80,
20+
"tabWidth": 4,
21+
"useTabs": false,
22+
"singleQuote": false,
23+
"bracketSpacing": false
24+
}
25+
}
26+
]
27+
}

.solcover.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
skipFiles: ['mock', 'test', 'vendor'],
3+
};

.solhint.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"extends": "solhint:recommended",
3+
"rules": {
4+
"compiler-version": "off",
5+
"func-visibility": ["warn", { "ignoreConstructors": true }],
6+
"not-rely-on-time": "off",
7+
"no-empty-blocks": "off",
8+
"no-global-import": "off",
9+
"func-name-mixedcase": "off",
10+
"immutable-vars-naming": "off",
11+
"gas-custom-errors": "off"
12+
}
13+
}

.solhintignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
node_modules
2+
.env
3+
dist
4+
5+
# Hardhat files
6+
/cache
7+
/artifacts
8+
9+
# TypeChain files
10+
/typechain
11+
/typechain-types
12+
13+
# solidity-coverage files
14+
/coverage
15+
/coverage.json
16+
17+
gas_report
18+
19+
contracts/vendor

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 API3 Foundation
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
# data-feed-proxy-combinators
1+
# data-feed-proxy-combinators
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.27;
3+
4+
import "@api3/contracts/interfaces/IApi3ReaderProxy.sol";
5+
import "./interfaces/IInverseApi3ReaderProxyV1.sol";
6+
7+
/// @title An immutable proxy contract that inverts the value returned by an
8+
/// IApi3ReaderProxy data feed
9+
/// @dev This contract implements the AggregatorV2V3Interface to be compatible
10+
/// with Chainlink aggregators. This allows the contract to be used as a drop-in
11+
/// replacement for Chainlink aggregators in existing dApps.
12+
/// Refer to https://github.com/api3dao/migrate-from-chainlink-to-api3 for more
13+
/// information about the Chainlink interface implementation.
14+
contract InverseApi3ReaderProxyV1 is IInverseApi3ReaderProxyV1 {
15+
/// @notice IApi3ReaderProxy contract address
16+
address public immutable override proxy;
17+
18+
/// @param proxy_ IApi3ReaderProxy contract address
19+
constructor(address proxy_) {
20+
if (proxy_ == address(0)) {
21+
revert ZeroProxyAddress();
22+
}
23+
proxy = proxy_;
24+
}
25+
26+
/// @notice Returns the inverted value of the underlying IApi3ReaderProxy
27+
/// @dev This inverts the 18-decimal fixed-point value using 1e36 / value.
28+
/// The operation will revert if `baseValue` is zero (division by zero) or if
29+
/// `baseValue` is so small (yet non-zero) that the resulting inverted value
30+
/// would overflow the `int224` type.
31+
/// @return value Inverted value of the underlying proxy
32+
/// @return timestamp Timestamp from the underlying proxy
33+
function read()
34+
public
35+
view
36+
override
37+
returns (int224 value, uint32 timestamp)
38+
{
39+
(int224 baseValue, uint32 baseTimestamp) = IApi3ReaderProxy(proxy)
40+
.read();
41+
42+
value = int224((1e36) / int256(baseValue));
43+
timestamp = baseTimestamp;
44+
}
45+
46+
/// @dev AggregatorV2V3Interface users are already responsible with
47+
/// validating the values that they receive (e.g., revert if the spot price
48+
/// of an asset is negative). Therefore, this contract omits validation.
49+
function latestAnswer() external view override returns (int256 value) {
50+
(value, ) = read();
51+
}
52+
53+
/// @dev A Chainlink feed contract returns the block timestamp at which the
54+
/// feed was last updated. On the other hand, an Api3 feed timestamp
55+
/// denotes the point in time at which the first-party oracles signed the
56+
/// data used to do the last update. We find this to be a reasonable
57+
/// approximation, considering that usually the timestamp is only used to
58+
/// check if the last update is stale.
59+
function latestTimestamp()
60+
external
61+
view
62+
override
63+
returns (uint256 timestamp)
64+
{
65+
(, timestamp) = read();
66+
}
67+
68+
/// @dev Api3 feeds are updated asynchronously and not in rounds
69+
function latestRound() external pure override returns (uint256) {
70+
revert FunctionIsNotSupported();
71+
}
72+
73+
/// @dev Functions that use the round ID as an argument are not supported
74+
function getAnswer(uint256) external pure override returns (int256) {
75+
revert FunctionIsNotSupported();
76+
}
77+
78+
/// @dev Functions that use the round ID as an argument are not supported
79+
function getTimestamp(uint256) external pure override returns (uint256) {
80+
revert FunctionIsNotSupported();
81+
}
82+
83+
/// @dev Api3 feeds always use 18 decimals
84+
function decimals() external pure override returns (uint8) {
85+
return 18;
86+
}
87+
88+
/// @dev Underlying proxy dApp ID and dAPI name act as the description, and
89+
/// this is left empty to save gas on contract deployment
90+
function description() external pure override returns (string memory) {
91+
return "";
92+
}
93+
94+
/// @dev A unique version is chosen to easily check if an unverified
95+
/// contract that acts as a Chainlink feed is a InverseApi3ReaderProxyV1
96+
function version() external pure override returns (uint256) {
97+
return 4915;
98+
}
99+
100+
/// @dev Functions that use the round ID as an argument are not supported
101+
function getRoundData(
102+
uint80
103+
)
104+
external
105+
pure
106+
override
107+
returns (uint80, int256, uint256, uint256, uint80)
108+
{
109+
revert FunctionIsNotSupported();
110+
}
111+
112+
/// @dev Rounds IDs are returned as `0` as invalid values.
113+
/// Similar to `latestAnswer()`, we leave the validation of the returned
114+
/// value to the caller.
115+
function latestRoundData()
116+
external
117+
view
118+
override
119+
returns (
120+
uint80 roundId,
121+
int256 answer,
122+
uint256 startedAt,
123+
uint256 updatedAt,
124+
uint80 answeredInRound
125+
)
126+
{
127+
roundId = answeredInRound = 0;
128+
(answer, startedAt) = read();
129+
updatedAt = startedAt;
130+
}
131+
}

0 commit comments

Comments
 (0)