Description:
Smart contract deployed on Ethereum with Oracle features.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/*
PriceOracleFullERC165.sol
--------------------------
- Manual or oracle-based price updates
- Optional Chainlink integration
- Human-readable + machine-readable price getters
- ERC-165 interface detection (IPriceOracle)
*/
/// -----------------------------------------------------------------------
/// ERC-165 Interface
/// -----------------------------------------------------------------------
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
/// -----------------------------------------------------------------------
/// Price Oracle Interface
/// -----------------------------------------------------------------------
interface IPriceOracle is IERC165 {
function getPrice() external view returns (uint256 price, uint8 decimals, uint256 updatedAt);
function getPriceString() external view returns (string memory);
}
/// -----------------------------------------------------------------------
/// Chainlink Aggregator Interface
/// -----------------------------------------------------------------------
interface AggregatorV3Interface {
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function decimals() external view returns (uint8);
}
/// -----------------------------------------------------------------------
/// Main Contract
/// -----------------------------------------------------------------------
contract PriceOracleFullERC165 is IPriceOracle {
address public owner;
uint256 private _price;
uint8 private _decimals;
uint256 public lastUpdated;
mapping(address => bool) public isOracle;
event PriceUpdated(address indexed by, uint256 price, uint8 decimals, uint256 timestamp);
event OracleAdded(address indexed oracle);
event OracleRemoved(address indexed oracle);
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
modifier onlyOracle() {
require(isOracle[msg.sender], "Not oracle");
_;
}
constructor(uint256 initialPrice, uint8 initialDecimals) {
owner = msg.sender;
_setPrice(initialPrice, initialDecimals);
}
// ---------------- Owner + Oracle Management ----------------
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "Zero address");
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
function addOracle(address oracle) external onlyOwner {
isOracle[oracle] = true;
emit OracleAdded(oracle);
}
function removeOracle(address oracle) external onlyOwner {
isOracle[oracle] = false;
emit OracleRemoved(oracle);
}
// ---------------- Price Updates ----------------
function setPrice(uint256 price, uint8 decimals) external onlyOwner {
_setPrice(price, decimals);
}
function oracleSetPrice(uint256 price, uint8 decimals) external onlyOracle {
_setPrice(price, decimals);
}
function updateFromChainlink(address aggregator) external onlyOwner {
AggregatorV3Interface feed = AggregatorV3Interface(aggregator);
(, int256 answer, , , ) = feed.latestRoundData();
require(answer > 0, "Invalid feed answer");
uint8 feedDecimals = feed.decimals();
_setPrice(uint256(answer), feedDecimals);
}
function _setPrice(uint256 price, uint8 decimals) internal {
require(price > 0, "Invalid price");
_price = price;
_decimals = decimals;
lastUpdated = block.timestamp;
emit PriceUpdated(msg.sender, price, decimals, block.timestamp);
}
// ---------------- Public View Functions ----------------
/// Machine-readable version for wallets & explorers
function getPrice() external view override returns (uint256 price, uint8 decimals, uint256 updatedAt) {
return (_price, _decimals, lastUpdated);
}
/// Human-readable helper for UIs
function getPriceString() external view override returns (string memory) {
uint256 integerPart = _price / (10 ** _decimals);
uint256 fractionalPart = _price % (10 ** _decimals);
bytes memory fracStr = bytes(_uintToString(fractionalPart));
uint8 missingZeros = _decimals > fracStr.length ? _decimals - uint8(fracStr.length) : 0;
string memory paddedFraction = string(abi.encodePacked(_repeat("0", missingZeros), fracStr));
return string(abi.encodePacked(_uintToString(integerPart), ".", paddedFraction, " USD"));
}
// ---------------- ERC-165 Interface Support ----------------
function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
return
interfaceId == type(IERC165).interfaceId || // 0x01ffc9a7
interfaceId == type(IPriceOracle).interfaceId; // custom oracle interface
}
// ---------------- Internal Helpers ----------------
function _uintToString(uint256 v) internal pure returns (string memory) {
if (v == 0) return "0";
uint256 len;
uint256 j = v;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint256 k = len;
j = v;
while (j != 0) {
k--;
bstr[k] = bytes1(uint8(48 + j % 10));
j /= 10;
}
return string(bstr);
}
function _repeat(string memory s, uint8 n) internal pure returns (string memory) {
bytes memory repeated;
for (uint8 i = 0; i < n; i++) repeated = abi.encodePacked(repeated, s);
return string(repeated);
}
}
Submitted on: 2025-10-14 11:41:44
Comments
Log in to comment.
No comments yet.