Skip to content

Commit 4a326f6

Browse files
Merge pull request #253 from gildlab/2025-10-27-pyth
pyth oracle
2 parents b6b1b07 + 8579c39 commit 4a326f6

File tree

6 files changed

+60
-2
lines changed

6 files changed

+60
-2
lines changed

.gas-snapshot

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ OffchainAssetReceiptVaultOwnerFreezeUntilTest:testTokenDepositFrozen(uint256) (r
166166
OffchainAssetReceiptVaultOwnerFreezeUntilTest:testTokenMintFrozen(uint256) (runs: 256, μ: 369652, ~: 376465)
167167
OffchainAssetReceiptVaultOwnerFreezeUntilTest:testTokenRedeemFrozen(uint256) (runs: 256, μ: 334722, ~: 340175)
168168
OffchainAssetReceiptVaultOwnerFreezeUntilTest:testTokenRedepositFrozen(uint256) (runs: 256, μ: 443837, ~: 450650)
169-
OffchainAssetReceiptVaultOwnerFreezeUntilTest:testTokenTransferFroze(uint256) (runs: 257, μ: 326674, ~: 333569)
169+
OffchainAssetReceiptVaultOwnerFreezeUntilTest:testTokenTransferFroze(uint256) (runs: 256, μ: 326750, ~: 333569)
170170
OffchainAssetReceiptVaultOwnerFreezeUntilTest:testTokenTransferNotFroze() (gas: 258229)
171171
OffchainAssetReceiptVaultOwnerFreezeUntilTest:testTokenWithdrawFrozen(uint256) (runs: 256, μ: 334875, ~: 340328)
172172
OffchainAssetReceiptVaultPaymentMintAuthorizerV1ConstructTest:testOffchainAssetReceiptVaultPaymentMintAuthorizerV1Construct() (gas: 2516599)

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@
2222
[submodule "lib/rain.verify.interface"]
2323
path = lib/rain.verify.interface
2424
url = https://github.com/rainlanguage/rain.verify.interface
25+
[submodule "lib/rain.pyth"]
26+
path = lib/rain.pyth
27+
url = https://github.com/rainlanguage/rain.pyth

foundry.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ remappings = [
1616
"chainlink/=lib/rain.chainlink/lib/chainlink/contracts/src/",
1717
"rain.math.fixedpoint/=lib/rain.math.fixedpoint/src/",
1818
"rain.extrospection/=lib/rain.factory/lib/rain.extrospection/src/",
19+
"rain.math.float/=lib/rain.flare/lib/rain.interpreter/lib/rain.interpreter.interface/lib/rain.math.float/src/",
1920
]
2021

2122
bytecode_hash = "none"

lib/rain.pyth

Submodule rain.pyth added at 71ea980

slither.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"detectors_to_exclude": "solc-version,block-timestamp,unused-imports,different-pragma-directives-are-used,assembly-usage",
3-
"filter_paths": "lib/openzeppelin-contracts,lib/rain.tier.interface,test/,node_modules"
3+
"filter_paths": "lib/openzeppelin-contracts,lib/rain.tier.interface,test/,node_modules,rain.math.float,rain.math.fixedpoint"
44
}

src/concrete/oracle/PythOracle.sol

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// SPDX-License-Identifier: LicenseRef-DCL-1.0
2+
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
3+
pragma solidity =0.8.25;
4+
5+
import {PriceOracleV2} from "../../abstract/PriceOracleV2.sol";
6+
import {IPyth} from "pyth-sdk/IPyth.sol";
7+
import {PythStructs} from "pyth-sdk/PythStructs.sol";
8+
import {LibDecimalFloat, Float} from "rain.math.float/lib/LibDecimalFloat.sol";
9+
10+
error NonPositivePrice(int256 price);
11+
12+
struct PythOracleConfig {
13+
bytes32 priceFeedId;
14+
uint256 staleAfter;
15+
IPyth pythContract;
16+
}
17+
18+
contract PythOracle is PriceOracleV2 {
19+
event Construction(address sender, PythOracleConfig config);
20+
21+
//slither-disable-next-line naming-convention
22+
bytes32 public immutable I_PRICE_FEED_ID;
23+
//slither-disable-next-line naming-convention
24+
uint256 public immutable I_STALE_AFTER;
25+
//slither-disable-next-line naming-convention
26+
IPyth public immutable I_PYTH_CONTRACT;
27+
28+
constructor(PythOracleConfig memory config) {
29+
I_PRICE_FEED_ID = config.priceFeedId;
30+
I_STALE_AFTER = config.staleAfter;
31+
I_PYTH_CONTRACT = config.pythContract;
32+
33+
emit Construction(msg.sender, config);
34+
}
35+
36+
function _price() internal virtual override returns (uint256) {
37+
// Slither false positive, confidence is checked here.
38+
// slither-disable-next-line pyth-unchecked-confidence
39+
PythStructs.Price memory priceData = I_PYTH_CONTRACT.getPriceNoOlderThan(I_PRICE_FEED_ID, I_STALE_AFTER);
40+
int256 conservativePrice = int256(priceData.price) - int256(uint256(priceData.conf));
41+
if (conservativePrice <= 0) {
42+
revert NonPositivePrice(conservativePrice);
43+
}
44+
// It is safe to pack lossless here because the price data uses only
45+
// 64 bits while we have 224 bits for a packed signed coefficient, and
46+
// the exponent bit size is the same for both.
47+
Float conservativePriceFloat = LibDecimalFloat.packLossless(conservativePrice, priceData.expo);
48+
// We ignore precision loss here, truncating towards zero.
49+
//slither-disable-next-line unused-return
50+
(uint256 price18,) = LibDecimalFloat.toFixedDecimalLossy(conservativePriceFloat, 18);
51+
return price18;
52+
}
53+
}

0 commit comments

Comments
 (0)