Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
122 lines
4.7 KiB
Solidity
122 lines
4.7 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.23;
|
|
|
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
|
import "./AerePyth.sol";
|
|
|
|
/// Existing AereOracle interface (median multi-reporter feed, deployed 2026-05-07).
|
|
interface IAereOracleLegacy {
|
|
function getPrice(bytes32 symbol) external view returns (uint128 price, uint64 timestamp, uint256 contributors);
|
|
}
|
|
|
|
/**
|
|
* @title AereOracleAdapter
|
|
* @notice Unified price-query interface for AERE Network.
|
|
*
|
|
* Bridges between:
|
|
* - Legacy AereOracle (single multi-reporter median feed for BTC/USD + ETH/USD)
|
|
* - AerePyth (Pyth-compatible pull oracle; 700+ feeds when public Pyth network onboards us)
|
|
*
|
|
* Routing logic (per symbol):
|
|
* - If a Pyth feed ID is registered for the symbol, prefer Pyth (newer, more
|
|
* trustworthy, signed by publisher set).
|
|
* - Else fall back to legacy AereOracle.
|
|
* - If neither has the symbol, revert.
|
|
*
|
|
* This adapter lets every AERE dApp keep using a single oracle address and one
|
|
* `getPrice(symbol)` signature, while the underlying data source migrates
|
|
* from AereOracle → AerePyth → canonical Pyth as the network matures.
|
|
*
|
|
* Symbol convention (bytes32):
|
|
* keccak256("BTC/USD"), keccak256("ETH/USD"), keccak256("AERE/USD"), etc.
|
|
*/
|
|
contract AereOracleAdapter is Ownable {
|
|
IAereOracleLegacy public legacy;
|
|
AerePyth public pyth;
|
|
|
|
/// symbol (keccak256) → Pyth price feed ID. If unset, fall back to legacy.
|
|
mapping(bytes32 => bytes32) public pythFeedId;
|
|
|
|
/// Maximum age (seconds) accepted for legacy oracle reads.
|
|
uint256 public legacyMaxAge = 600;
|
|
|
|
event PythRegistered(bytes32 indexed symbol, bytes32 indexed pythFeedId);
|
|
event SourceUpdated(string source, address indexed addr);
|
|
|
|
constructor(IAereOracleLegacy _legacy, AerePyth _pyth) {
|
|
legacy = _legacy;
|
|
pyth = _pyth;
|
|
}
|
|
|
|
// ───────────────────── Admin ─────────────────────
|
|
|
|
function setLegacy(IAereOracleLegacy _legacy) external onlyOwner {
|
|
legacy = _legacy;
|
|
emit SourceUpdated("legacy", address(_legacy));
|
|
}
|
|
|
|
function setPyth(AerePyth _pyth) external onlyOwner {
|
|
pyth = _pyth;
|
|
emit SourceUpdated("pyth", address(_pyth));
|
|
}
|
|
|
|
function registerPythFeed(bytes32 symbol, bytes32 feedId) external onlyOwner {
|
|
pythFeedId[symbol] = feedId;
|
|
emit PythRegistered(symbol, feedId);
|
|
}
|
|
|
|
function setLegacyMaxAge(uint256 _age) external onlyOwner {
|
|
legacyMaxAge = _age;
|
|
}
|
|
|
|
// ───────────────────── Unified read ─────────────────────
|
|
|
|
/**
|
|
* @notice Universal price read.
|
|
* @return price1e8 Price scaled to 1e8 (same as AereOracle's format).
|
|
* @return updatedAt unix seconds.
|
|
* @return source "pyth" or "legacy".
|
|
*/
|
|
function quote(bytes32 symbol) external view returns (uint256 price1e8, uint256 updatedAt, string memory source) {
|
|
bytes32 feedId = pythFeedId[symbol];
|
|
if (feedId != bytes32(0)) {
|
|
PythPrice memory p = pyth.getPriceUnsafe(feedId);
|
|
require(p.publishTime > 0, "Adapter: no pyth data");
|
|
// Pyth stores price + exponent; normalise to 1e8.
|
|
// expo is negative for fractional prices (e.g. -8 for $30000.12345678).
|
|
uint256 abs;
|
|
if (p.price < 0) {
|
|
// Negative price means market closed or invalid; revert.
|
|
revert("Adapter: negative price");
|
|
}
|
|
abs = uint256(uint64(p.price));
|
|
int32 expo = p.expo;
|
|
if (expo == -8) {
|
|
price1e8 = abs;
|
|
} else if (expo > -8) {
|
|
// expo is e.g. -6 (USDC), -2 (some equities). Scale up.
|
|
price1e8 = abs * (10 ** uint256(int256(-8 - expo)));
|
|
} else {
|
|
// expo is e.g. -12, -18 (some assets). Scale down.
|
|
price1e8 = abs / (10 ** uint256(int256(expo + 8)));
|
|
}
|
|
updatedAt = p.publishTime;
|
|
source = "pyth";
|
|
return (price1e8, updatedAt, source);
|
|
}
|
|
|
|
// Fall back to legacy AereOracle.
|
|
(uint128 lp, uint64 lts, ) = legacy.getPrice(symbol);
|
|
require(lp > 0, "Adapter: no legacy data");
|
|
require(block.timestamp - uint256(lts) <= legacyMaxAge, "Adapter: legacy stale");
|
|
price1e8 = uint256(lp);
|
|
updatedAt = uint256(lts);
|
|
source = "legacy";
|
|
}
|
|
|
|
/// Convenience: just return the price1e8.
|
|
function priceOf(bytes32 symbol) external view returns (uint256 price1e8) {
|
|
(price1e8, , ) = this.quote(symbol);
|
|
}
|
|
}
|