Skip to content

Commit 93362d2

Browse files
authored
Merge pull request #15 from api3dao/quanstamp-initial-report
Quanstamp initial report
2 parents 3503ca8 + 3ef9298 commit 93362d2

File tree

6 files changed

+37
-38
lines changed

6 files changed

+37
-38
lines changed

contracts/InverseApi3ReaderProxyV1.sol

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.27;
2+
pragma solidity 0.8.27;
33

44
import "@api3/contracts/interfaces/IApi3ReaderProxy.sol";
55
import "./interfaces/IInverseApi3ReaderProxyV1.sol";
@@ -24,10 +24,9 @@ contract InverseApi3ReaderProxyV1 is IInverseApi3ReaderProxyV1 {
2424
}
2525

2626
/// @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.
27+
/// @dev Calculates `int224(1e36) / baseValue`. The operation will revert if
28+
/// `baseValue` is zero. If `baseValue` is non-zero but its absolute value is
29+
/// greater than `1e36`, the result of the integer division will be `0`.
3130
/// @return value Inverted value of the underlying proxy
3231
/// @return timestamp Timestamp of the underlying proxy
3332
function read()
@@ -39,7 +38,11 @@ contract InverseApi3ReaderProxyV1 is IInverseApi3ReaderProxyV1 {
3938
(int224 baseValue, uint32 baseTimestamp) = IApi3ReaderProxy(proxy)
4039
.read();
4140

42-
value = int224((1e36) / int256(baseValue));
41+
if (baseValue == 0) {
42+
revert DivisionByZero();
43+
}
44+
45+
value = int224(1e36) / baseValue;
4346
timestamp = baseTimestamp;
4447
}
4548

contracts/NormalizedApi3ReaderProxyV1.sol

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.27;
2+
pragma solidity 0.8.27;
33

44
import "./interfaces/INormalizedApi3ReaderProxyV1.sol";
55

@@ -45,15 +45,9 @@ contract NormalizedApi3ReaderProxyV1 is INormalizedApi3ReaderProxyV1 {
4545

4646
/// @notice Returns the price of the underlying Chainlink feed normalized to
4747
/// 18 decimals.
48-
/// @dev Fetches an `int256` answer from the Chainlink feed and scales it
49-
/// to 18 decimals using pre-calculated factors. The result is cast to
50-
/// `int224` to conform to the `IApi3ReaderProxy` interface.
51-
/// IMPORTANT: If the normalized `int256` value is outside the `int224`
52-
/// range, this cast causes silent truncation and data loss. Deployers
53-
/// must verify that the source feed's characteristics (value magnitude
54-
/// and original decimals) ensure the 18-decimal normalized value fits
55-
/// `int224`. Scaling arithmetic (prior to cast) reverts on `int256`
56-
/// overflow.
48+
/// @dev Fetches and scales the Chainlink feed's `int256` answer.
49+
/// The scaled `int256` result is then cast to `int224`. This cast is
50+
/// unchecked for gas optimization and may silently truncate.
5751
/// @return value The normalized signed fixed-point value with 18 decimals
5852
/// @return timestamp The updatedAt timestamp of the feed
5953
function read()

contracts/PriceCappedApi3ReaderProxyV1.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.27;
2+
pragma solidity 0.8.27;
33

44
import "@api3/contracts/interfaces/IApi3ReaderProxy.sol";
55
import "./interfaces/IPriceCappedApi3ReaderProxyV1.sol";

contracts/ProductApi3ReaderProxyV1.sol

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.27;
2+
pragma solidity 0.8.27;
33

44
import "@api3/contracts/interfaces/IApi3ReaderProxy.sol";
55
import "./interfaces/IProductApi3ReaderProxyV1.sol";
@@ -33,13 +33,14 @@ contract ProductApi3ReaderProxyV1 is IProductApi3ReaderProxyV1 {
3333

3434
/// @notice Returns the current value and timestamp of the rate composition
3535
/// between two IApi3ReaderProxy proxies by multiplying their values
36-
/// @dev There is a risk of multiplication overflowing if the result exceeds
37-
/// `int256` bounds. The returned timestamp is `block.timestamp`, marking
38-
/// when this newly derived product value was computed on-chain.
39-
/// Timestamps from underlying `IApi3ReaderProxy` feeds are not aggregated.
40-
/// Their diverse nature (see `IApi3ReaderProxy` interface for details like
41-
/// off-chain origins or varying update cadences) makes aggregation complex
42-
/// and potentially misleading for this product's timestamp.
36+
/// @dev Calculates product as `(int256(value1) * int256(value2)) / 1e18`.
37+
/// The initial multiplication `int256(value1) * int256(value2)` may revert
38+
/// on `int256` overflow. The final `int256` result of the full expression
39+
/// is then cast to `int224`. This cast is unchecked for gas optimization
40+
/// and may silently truncate if the result exceeds `int224` limits.
41+
/// The returned timestamp is `block.timestamp`, reflecting the on-chain
42+
/// computation time of the product. Underlying feed timestamps are not
43+
/// aggregated due to complexity and potential for misinterpretation.
4344
/// @return value Value of the product of the two proxies
4445
/// @return timestamp Timestamp of the current block
4546
function read()

contracts/adapters/ScaledApi3FeedProxyV1.sol

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.27;
2+
pragma solidity 0.8.27;
33

44
import "@api3/contracts/interfaces/IApi3ReaderProxy.sol";
55
import "./interfaces/IScaledApi3FeedProxyV1.sol";
66

77
/// @title An immutable Chainlink AggregatorV2V3Interface feed contract that
88
/// scales the value of an IApi3ReaderProxy data feed to a target number of
99
/// decimals
10-
/// @dev This contract assumes the source proxy always returns values with
11-
/// 18 decimals (as all IApi3ReaderProxy-compatible proxies do)
10+
/// @dev This contract reads an `int224` value (assumed to be 18 decimals)
11+
/// from the underlying `IApi3ReaderProxy` and scales it to `targetDecimals`.
12+
/// The scaling arithmetic uses `int256` for intermediate results, allowing the
13+
/// scaled value to exceed `int224` limits if upscaling significantly; it will
14+
/// revert on `int256` overflow.
15+
/// When downscaling, integer division (`proxyValue / scalingFactor`) is used,
16+
/// which truncates and may lead to precision loss. Integrators must carefully
17+
/// consider this potential precision loss for their specific use case.
1218
contract ScaledApi3FeedProxyV1 is IScaledApi3FeedProxyV1 {
1319
/// @notice IApi3ReaderProxy contract address
1420
address public immutable override proxy;
@@ -133,15 +139,10 @@ contract ScaledApi3FeedProxyV1 is IScaledApi3FeedProxyV1 {
133139

134140
/// @notice Reads a value from the underlying `IApi3ReaderProxy` and
135141
/// scales it to `targetDecimals`.
136-
/// @dev Reads an `int224` value (assumed to be 18 decimals) from the
137-
/// underlying `IApi3ReaderProxy`. This value is then scaled to
138-
/// `targetDecimals` using pre-calculated factors. The scaling arithmetic
139-
/// (e.g., `proxyValue * scalingFactor`) involves an `int224` (`proxyValue`)
140-
/// and an `int256` (`scalingFactor`). `proxyValue` is implicitly promoted
141-
/// to `int256` for this operation, resulting in an `int256` value.
142-
/// This allows the scaled result to exceed the `int224` range, provided
143-
/// it fits within `int256`. Arithmetic operations will revert on `int256`
144-
/// overflow. The function returns the scaled value as an `int256`.
142+
/// @dev Reads from the underlying proxy and applies scaling to
143+
/// `targetDecimals`. Upscaling uses multiplication; downscaling uses integer
144+
/// division (which truncates). All scaling arithmetic is performed using
145+
/// `int256`.
145146
/// @return value The scaled signed fixed-point value with `targetDecimals`.
146147
/// @return timestamp The timestamp from the underlying proxy.
147148
function _read() internal view returns (int256 value, uint32 timestamp) {

contracts/test/MockAggregatorV2V3.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.27;
2+
pragma solidity 0.8.27;
33

44
import "../vendor/@chainlink/contracts@1.2.0/src/v0.8/shared/interfaces/AggregatorV2V3Interface.sol";
55

0 commit comments

Comments
 (0)