Files
sre-06-oracles/packages/hardhat/deployments/sepolia/WhitelistOracle.json
han c18c66cca1
Some checks failed
Lint / ci (lts/*, ubuntu-latest) (push) Has been cancelled
feat: finish up challenges
2026-01-26 18:22:19 +07:00

290 lines
35 KiB
JSON

{
"address": "0x7ac886207F1fea709117b73B8c1e97c40f46ad9c",
"abi": [
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "EmptyArray",
"type": "error"
},
{
"inputs": [],
"name": "IndexOutOfBounds",
"type": "error"
},
{
"inputs": [],
"name": "NoOraclesAvailable",
"type": "error"
},
{
"inputs": [],
"name": "OnlyOwner",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "oracleAddress",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "oracleOwner",
"type": "address"
}
],
"name": "OracleAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "oracleAddress",
"type": "address"
}
],
"name": "OracleRemoved",
"type": "event"
},
{
"inputs": [],
"name": "STALE_DATA_WINDOW",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_owner",
"type": "address"
}
],
"name": "addOracle",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "getActiveOracleNodes",
"outputs": [
{
"internalType": "address[]",
"name": "",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getPrice",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "oracles",
"outputs": [
{
"internalType": "contract SimpleOracle",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "removeOracle",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
],
"transactionHash": "0xe7bf1985a4ac083403429b91d04d1af6150ae59448ce8596d5d250d548a9be41",
"receipt": {
"to": null,
"from": "0x23E53302800Ccd8a5b35cFA576B6eB73dab297B4",
"contractAddress": "0x7ac886207F1fea709117b73B8c1e97c40f46ad9c",
"transactionIndex": 48,
"gasUsed": "814772",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"blockHash": "0x89d50c2a3b549d5c8f917f8992f3a50b9462aca2cc76f37840aef9d6012b291c",
"transactionHash": "0xe7bf1985a4ac083403429b91d04d1af6150ae59448ce8596d5d250d548a9be41",
"logs": [],
"blockNumber": 10119858,
"cumulativeGasUsed": "18978613",
"status": 1,
"byzantium": true
},
"args": [],
"numDeployments": 1,
"solcInputHash": "5ddadefd5b01c44dd0bbf987b1598ce3",
"metadata": "{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyArray\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IndexOutOfBounds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoOraclesAvailable\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyOwner\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oracleAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oracleOwner\",\"type\":\"address\"}],\"name\":\"OracleAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oracleAddress\",\"type\":\"address\"}],\"name\":\"OracleRemoved\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"STALE_DATA_WINDOW\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"addOracle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getActiveOracleNodes\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"oracles\",\"outputs\":[{\"internalType\":\"contract SimpleOracle\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"removeOracle\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"addOracle(address)\":{\"details\":\"Creates a new SimpleOracle instance and adds it to the oracles array.\",\"params\":{\"_owner\":\"The address that will own the newly created oracle and can update its price\"}},\"getActiveOracleNodes()\":{\"details\":\"Iterates through all oracles and filters those with recent timestamps (within STALE_DATA_WINDOW). Uses a temporary array to collect active nodes, then creates a right-sized return array for gas optimization.\",\"returns\":{\"_0\":\"An array of addresses representing the currently active oracle contracts\"}},\"getPrice()\":{\"details\":\"Filters oracles with timestamps older than STALE_DATA_WINDOW, then calculates median of remaining valid prices. Uses StatisticsUtils for sorting and median calculation.\",\"returns\":{\"_0\":\"The median price from all active oracles\"}},\"removeOracle(uint256)\":{\"details\":\"Uses swap-and-pop pattern for gas-efficient removal. Order is not preserved. Reverts with IndexOutOfBounds, if the provided index is >= oracles.length.\",\"params\":{\"index\":\"The index of the oracle to remove from the oracles array\"}}},\"version\":1},\"userdoc\":{\"errors\":{\"EmptyArray()\":[{\"notice\":\"Errors //////\"}],\"OnlyOwner()\":[{\"notice\":\"Errors //////\"}]},\"events\":{\"OracleAdded(address,address)\":{\"notice\":\"Events /////\"}},\"kind\":\"user\",\"methods\":{\"addOracle(address)\":{\"notice\":\"Adds a new oracle to the whitelist by deploying a SimpleOracle contract (only contract owner)\"},\"constructor\":{\"notice\":\"Constructor ///\"},\"getActiveOracleNodes()\":{\"notice\":\"Returns the addresses of all oracles that have updated their price within the last STALE_DATA_WINDOW\"},\"getPrice()\":{\"notice\":\"Returns the aggregated price from all active oracles using median calculation\"},\"owner()\":{\"notice\":\"State Variables //\"},\"removeOracle(uint256)\":{\"notice\":\"Removes an oracle from the whitelist by its array index (only contract owner)\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/00_Whitelist/WhitelistOracle.sol\":\"WhitelistOracle\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/00_Whitelist/SimpleOracle.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\ncontract SimpleOracle {\\n /////////////////\\n /// Errors //////\\n /////////////////\\n\\n error OnlyOwner();\\n\\n //////////////////////\\n /// State Variables //\\n //////////////////////\\n\\n uint256 public price;\\n uint256 public timestamp;\\n address public owner;\\n\\n ////////////////\\n /// Events /////\\n ////////////////\\n\\n event PriceUpdated(uint256 newPrice);\\n\\n ///////////////////\\n /// Constructor ///\\n ///////////////////\\n\\n constructor(address _owner) {\\n owner = _owner;\\n }\\n\\n ///////////////////\\n /// Modifiers /////\\n ///////////////////\\n\\n /**\\n * @notice Modifier to restrict function access to the contract owner\\n * @dev Currently disabled to make it easy for you to impersonate the owner\\n */\\n modifier onlyOwner() {\\n // Intentionally removing the owner requirement to make it easy for you to impersonate the owner\\n // if (msg.sender != owner) revert OnlyOwner();\\n _;\\n }\\n\\n ///////////////////\\n /// Functions /////\\n ///////////////////\\n\\n /**\\n * @notice Updates the oracle price with a new value (only contract owner)\\n * @dev Sets the price and records the current block timestamp for freshness tracking.\\n * Emits PriceUpdated event upon successful update.\\n * @param _newPrice The new price value to set for this oracle\\n */\\n function setPrice(uint256 _newPrice) public onlyOwner {\\n price = _newPrice;\\n timestamp = block.timestamp;\\n emit PriceUpdated(_newPrice);\\n }\\n\\n /**\\n * @notice Returns the current price and its timestamp\\n * @dev Provides both the stored price value and when it was last updated.\\n * Used by aggregators to determine price freshness.\\n * @return price The current price stored in this oracle\\n * @return timestamp The block timestamp when the price was last updated\\n */\\n function getPrice() public view returns (uint256, uint256) {\\n return (price, timestamp);\\n }\\n}\\n\",\"keccak256\":\"0xf7824e681abc476a008bc4aa06b41e0c9d54e3a84db98ae142dae10eb022275b\",\"license\":\"MIT\"},\"contracts/00_Whitelist/WhitelistOracle.sol\":{\"content\":\"//SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\nimport \\\"./SimpleOracle.sol\\\";\\nimport { StatisticsUtils } from \\\"../utils/StatisticsUtils.sol\\\";\\n\\ncontract WhitelistOracle {\\n using StatisticsUtils for uint256[];\\n\\n /////////////////\\n /// Errors //////\\n /////////////////\\n\\n error OnlyOwner();\\n error IndexOutOfBounds();\\n error NoOraclesAvailable();\\n\\n //////////////////////\\n /// State Variables //\\n //////////////////////\\n\\n address public owner;\\n SimpleOracle[] public oracles;\\n uint256 public constant STALE_DATA_WINDOW = 24 seconds;\\n\\n ////////////////\\n /// Events /////\\n ////////////////\\n\\n event OracleAdded(address oracleAddress, address oracleOwner);\\n event OracleRemoved(address oracleAddress);\\n\\n ///////////////////\\n /// Modifiers /////\\n ///////////////////\\n\\n /**\\n * @notice Modifier to restrict function access to the contract owner\\n * @dev Currently disabled to make it easy for you to impersonate the owner\\n */\\n modifier onlyOwner() {\\n // if (msg.sender != owner) revert OnlyOwner();\\n _;\\n }\\n\\n ///////////////////\\n /// Constructor ///\\n ///////////////////\\n\\n constructor() {\\n owner = msg.sender;\\n }\\n\\n ///////////////////\\n /// Functions /////\\n ///////////////////\\n\\n /**\\n * @notice Adds a new oracle to the whitelist by deploying a SimpleOracle contract (only contract owner)\\n * @dev Creates a new SimpleOracle instance and adds it to the oracles array.\\n * @param _owner The address that will own the newly created oracle and can update its price\\n */\\n function addOracle(address _owner) public onlyOwner {\\n SimpleOracle newOracle = new SimpleOracle(_owner);\\n oracles.push(newOracle);\\n emit OracleAdded(address(newOracle), _owner);\\n }\\n\\n /**\\n * @notice Removes an oracle from the whitelist by its array index (only contract owner)\\n * @dev Uses swap-and-pop pattern for gas-efficient removal. Order is not preserved.\\n * Reverts with IndexOutOfBounds, if the provided index is >= oracles.length.\\n * @param index The index of the oracle to remove from the oracles array\\n */\\n function removeOracle(uint256 index) public onlyOwner {\\n uint256 oraclesSize = oracles.length;\\n if (index >= oraclesSize) revert IndexOutOfBounds();\\n\\n address deletedOracle = address(oracles[index]);\\n if (index != oraclesSize - 1) {\\n oracles[index] = oracles[oraclesSize - 1];\\n }\\n \\n oracles.pop();\\n emit OracleRemoved(deletedOracle);\\n }\\n\\n /**\\n * @notice Returns the aggregated price from all active oracles using median calculation\\n * @dev Filters oracles with timestamps older than STALE_DATA_WINDOW, then calculates median\\n * of remaining valid prices. Uses StatisticsUtils for sorting and median calculation.\\n * @return The median price from all active oracles\\n */\\n function getPrice() public view returns (uint256) {\\n if (oracles.length == 0) revert NoOraclesAvailable();\\n uint256[] memory prices = new uint256[](oracles.length);\\n uint256 priceIndex = 0;\\n uint256 currentTime = block.timestamp;\\n\\n for (uint256 i = 0; i < oracles.length; i++) {\\n (uint256 price, uint256 timestamp) = oracles[i].getPrice();\\n\\tif (currentTime - timestamp < STALE_DATA_WINDOW) {\\n\\t prices[priceIndex] = price;\\n\\t priceIndex++;\\n\\t}\\n }\\n\\n uint256[] memory fixedPrices = new uint256[](priceIndex);\\n for (uint256 i = 0; i < priceIndex; i++) {\\n fixedPrices[i] = prices[i];\\n }\\n\\n fixedPrices.sort();\\n return fixedPrices.getMedian();\\n }\\n\\n /**\\n * @notice Returns the addresses of all oracles that have updated their price within the last STALE_DATA_WINDOW\\n * @dev Iterates through all oracles and filters those with recent timestamps (within STALE_DATA_WINDOW).\\n * Uses a temporary array to collect active nodes, then creates a right-sized return array\\n * for gas optimization.\\n * @return An array of addresses representing the currently active oracle contracts\\n */\\n function getActiveOracleNodes() public view returns (address[] memory) {\\n address[] memory activeOracles = new address[](oracles.length);\\n uint256 oracleIndex = 0;\\n uint256 currentTime = block.timestamp;\\n\\n for (uint256 i = 0; i < oracles.length; i++) {\\n (, uint256 timestamp) = oracles[i].getPrice();\\n\\tif (currentTime - timestamp < STALE_DATA_WINDOW) {\\n\\t activeOracles[oracleIndex] = address(oracles[i]);\\n\\t oracleIndex++;\\n\\t}\\n }\\n\\n address[] memory fixedActiveOracles = new address[](oracleIndex);\\n for (uint256 i = 0; i < oracleIndex; i++) {\\n fixedActiveOracles[i] = activeOracles[i];\\n }\\n\\n return fixedActiveOracles;\\n }\\n}\\n\",\"keccak256\":\"0xf2436dd59b378d3b1a9ec8033beda6fe3cbe21f6d3f5c93b0d982bebd874630e\",\"license\":\"MIT\"},\"contracts/utils/StatisticsUtils.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity >=0.8.0 <0.9.0;\\n\\nlibrary StatisticsUtils {\\n /////////////////\\n /// Errors //////\\n /////////////////\\n\\n error EmptyArray();\\n\\n ///////////////////\\n /// Functions /////\\n ///////////////////\\n\\n /**\\n * @notice Sorts an array of uint256 values in ascending order using selection sort\\n * @dev Uses selection sort algorithm which is not gas-efficient but acceptable for small arrays.\\n * This implementation mimics the early MakerDAO Medianizer exactly.\\n * Modifies the input array in-place.\\n * @param arr The array of uint256 values to sort in ascending order\\n */\\n function sort(uint256[] memory arr) internal pure {\\n uint256 n = arr.length;\\n for (uint256 i = 0; i < n; i++) {\\n uint256 minIndex = i;\\n for (uint256 j = i + 1; j < n; j++) {\\n if (arr[j] < arr[minIndex]) {\\n minIndex = j;\\n }\\n }\\n if (minIndex != i) {\\n (arr[i], arr[minIndex]) = (arr[minIndex], arr[i]);\\n }\\n }\\n }\\n\\n /**\\n * @notice Calculates the median value from a sorted array of uint256 values\\n * @dev For arrays with even length, returns the average of the two middle elements.\\n * For arrays with odd length, returns the middle element.\\n * Assumes the input array is already sorted in ascending order.\\n * @param arr The sorted array of uint256 values to calculate median from\\n * @return The median value as a uint256\\n */\\n function getMedian(uint256[] memory arr) internal pure returns (uint256) {\\n uint256 length = arr.length;\\n if (length == 0) revert EmptyArray();\\n if (length % 2 == 0) {\\n return (arr[length / 2 - 1] + arr[length / 2]) / 2;\\n } else {\\n return arr[length / 2];\\n }\\n }\\n}\\n\",\"keccak256\":\"0xc0949844270a074ee4289211c32b5e33062343fb5ae282c314a944e344e609cc\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b50600080546001600160a01b03191633179055610d60806100326000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c8063977e79231161005b578063977e7923146100da57806398d5fdca146100f0578063df5dd1a5146100f8578063fb152f8c1461010b57600080fd5b80635b69a7d81461008257806380935dbf146100b25780638da5cb5b146100c7575b600080fd5b61009561009036600461099f565b610120565b6040516001600160a01b0390911681526020015b60405180910390f35b6100c56100c036600461099f565b61014a565b005b600054610095906001600160a01b031681565b6100e2601881565b6040519081526020016100a9565b6100e2610298565b6100c56101063660046109b8565b6104ba565b610113610585565b6040516100a991906109e1565b6001818154811061013057600080fd5b6000918252602090912001546001600160a01b0316905081565b60015480821061016d57604051634e23d03560e01b815260040160405180910390fd5b60006001838154811061018257610182610a2e565b6000918252602090912001546001600160a01b031690506101a4600183610a5a565b83146102215760016101b68184610a5a565b815481106101c6576101c6610a2e565b600091825260209091200154600180546001600160a01b0390921691859081106101f2576101f2610a2e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b600180548061023257610232610a73565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03831681527f9c8e7d83025bef8a04c664b2f753f64b8814bdb7e27291d7e50935f18cc3c712910160405180910390a1505050565b60015460009081036102bd5760405163d9aad26b60e01b815260040160405180910390fd5b60015460009067ffffffffffffffff8111156102db576102db610a89565b604051908082528060200260200182016040528015610304578160200160208202803683370190505b509050600042815b600154811015610402576000806001838154811061032c5761032c610a2e565b9060005260206000200160009054906101000a90046001600160a01b03166001600160a01b03166398d5fdca6040518163ffffffff1660e01b81526004016040805180830381865afa158015610386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103aa9190610a9f565b909250905060186103bb8286610a5a565b10156103ed57818686815181106103d4576103d4610a2e565b6020908102919091010152846103e981610ac3565b9550505b505080806103fa90610ac3565b91505061030c565b5060008267ffffffffffffffff81111561041e5761041e610a89565b604051908082528060200260200182016040528015610447578160200160208202803683370190505b50905060005b8381101561049e5784818151811061046757610467610a2e565b602002602001015182828151811061048157610481610a2e565b60209081029190910101528061049681610ac3565b91505061044d565b506104a8816107b8565b6104b1816108bd565b94505050505090565b6000816040516104c990610992565b6001600160a01b039091168152602001604051809103906000f0801580156104f5573d6000803e3d6000fd5b506001805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0319166001600160a01b038381169182179092556040805191825291851660208201529192507f828d2be040dede7698182e08dfa8bfbd663c879aee772509c4a2bd961d0ed43f910160405180910390a15050565b60015460609060009067ffffffffffffffff8111156105a6576105a6610a89565b6040519080825280602002602001820160405280156105cf578160200160208202803683370190505b509050600042815b600154811015610706576000600182815481106105f6576105f6610a2e565b9060005260206000200160009054906101000a90046001600160a01b03166001600160a01b03166398d5fdca6040518163ffffffff1660e01b81526004016040805180830381865afa158015610650573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106749190610a9f565b9150601890506106848285610a5a565b10156106f3576001828154811061069d5761069d610a2e565b9060005260206000200160009054906101000a90046001600160a01b03168585815181106106cd576106cd610a2e565b6001600160a01b0390921660209283029190910190910152836106ef81610ac3565b9450505b50806106fe81610ac3565b9150506105d7565b5060008267ffffffffffffffff81111561072257610722610a89565b60405190808252806020026020018201604052801561074b578160200160208202803683370190505b50905060005b838110156107af5784818151811061076b5761076b610a2e565b602002602001015182828151811061078557610785610a2e565b6001600160a01b0390921660209283029190910190910152806107a781610ac3565b915050610751565b50949350505050565b805160005b818110156108b8578060006107d3826001610adc565b90505b8381101561082e578482815181106107f0576107f0610a2e565b602002602001015185828151811061080a5761080a610a2e565b6020026020010151101561081c578091505b8061082681610ac3565b9150506107d6565b508181146108a55783818151811061084857610848610a2e565b602002602001015184838151811061086257610862610a2e565b602002602001015185848151811061087c5761087c610a2e565b6020026020010186848151811061089557610895610a2e565b6020908102919091010191909152525b50806108b081610ac3565b9150506107bd565b505050565b80516000908082036108e25760405163521299a960e01b815260040160405180910390fd5b6108ed600282610b05565b600003610966576002836109018284610b19565b8151811061091157610911610a2e565b60200260200101518460016002856109299190610b19565b6109339190610a5a565b8151811061094357610943610a2e565b60200260200101516109559190610adc565b61095f9190610b19565b9392505050565b82610972600283610b19565b8151811061098257610982610a2e565b6020026020010151915050919050565b6101fd80610b2e83390190565b6000602082840312156109b157600080fd5b5035919050565b6000602082840312156109ca57600080fd5b81356001600160a01b038116811461095f57600080fd5b6020808252825182820181905260009190848201906040850190845b81811015610a225783516001600160a01b0316835292840192918401916001016109fd565b50909695505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115610a6d57610a6d610a44565b92915050565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60008060408385031215610ab257600080fd5b505080516020909101519092909150565b600060018201610ad557610ad5610a44565b5060010190565b80820180821115610a6d57610a6d610a44565b634e487b7160e01b600052601260045260246000fd5b600082610b1457610b14610aef565b500690565b600082610b2857610b28610aef565b50049056fe608060405234801561001057600080fd5b506040516101fd3803806101fd83398101604081905261002f91610054565b600280546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61016a806100936000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80638da5cb5b1461005c57806391b7f5ed1461008c57806398d5fdca146100a1578063a035b1fe146100bc578063b80777ea146100d3575b600080fd5b60025461006f906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61009f61009a36600461011b565b6100dc565b005b60005460015460408051928352602083019190915201610083565b6100c560005481565b604051908152602001610083565b6100c560015481565b6000819055426001556040518181527f66cbca4f3c64fecf1dcb9ce094abcf7f68c3450a1d4e3a8e917dd621edb4ebe09060200160405180910390a150565b60006020828403121561012d57600080fd5b503591905056fea26469706673582212207bce08ed1ca473e0dddb95384c49cc6f88540c7565db18724ec724cf923ea9a064736f6c63430008140033a26469706673582212204e374c48e5fc716aaca167c543b13ea08d2c65fe57957d69e3d79b85476514d764736f6c63430008140033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061007d5760003560e01c8063977e79231161005b578063977e7923146100da57806398d5fdca146100f0578063df5dd1a5146100f8578063fb152f8c1461010b57600080fd5b80635b69a7d81461008257806380935dbf146100b25780638da5cb5b146100c7575b600080fd5b61009561009036600461099f565b610120565b6040516001600160a01b0390911681526020015b60405180910390f35b6100c56100c036600461099f565b61014a565b005b600054610095906001600160a01b031681565b6100e2601881565b6040519081526020016100a9565b6100e2610298565b6100c56101063660046109b8565b6104ba565b610113610585565b6040516100a991906109e1565b6001818154811061013057600080fd5b6000918252602090912001546001600160a01b0316905081565b60015480821061016d57604051634e23d03560e01b815260040160405180910390fd5b60006001838154811061018257610182610a2e565b6000918252602090912001546001600160a01b031690506101a4600183610a5a565b83146102215760016101b68184610a5a565b815481106101c6576101c6610a2e565b600091825260209091200154600180546001600160a01b0390921691859081106101f2576101f2610a2e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b600180548061023257610232610a73565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03831681527f9c8e7d83025bef8a04c664b2f753f64b8814bdb7e27291d7e50935f18cc3c712910160405180910390a1505050565b60015460009081036102bd5760405163d9aad26b60e01b815260040160405180910390fd5b60015460009067ffffffffffffffff8111156102db576102db610a89565b604051908082528060200260200182016040528015610304578160200160208202803683370190505b509050600042815b600154811015610402576000806001838154811061032c5761032c610a2e565b9060005260206000200160009054906101000a90046001600160a01b03166001600160a01b03166398d5fdca6040518163ffffffff1660e01b81526004016040805180830381865afa158015610386573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103aa9190610a9f565b909250905060186103bb8286610a5a565b10156103ed57818686815181106103d4576103d4610a2e565b6020908102919091010152846103e981610ac3565b9550505b505080806103fa90610ac3565b91505061030c565b5060008267ffffffffffffffff81111561041e5761041e610a89565b604051908082528060200260200182016040528015610447578160200160208202803683370190505b50905060005b8381101561049e5784818151811061046757610467610a2e565b602002602001015182828151811061048157610481610a2e565b60209081029190910101528061049681610ac3565b91505061044d565b506104a8816107b8565b6104b1816108bd565b94505050505090565b6000816040516104c990610992565b6001600160a01b039091168152602001604051809103906000f0801580156104f5573d6000803e3d6000fd5b506001805480820182556000919091527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0319166001600160a01b038381169182179092556040805191825291851660208201529192507f828d2be040dede7698182e08dfa8bfbd663c879aee772509c4a2bd961d0ed43f910160405180910390a15050565b60015460609060009067ffffffffffffffff8111156105a6576105a6610a89565b6040519080825280602002602001820160405280156105cf578160200160208202803683370190505b509050600042815b600154811015610706576000600182815481106105f6576105f6610a2e565b9060005260206000200160009054906101000a90046001600160a01b03166001600160a01b03166398d5fdca6040518163ffffffff1660e01b81526004016040805180830381865afa158015610650573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106749190610a9f565b9150601890506106848285610a5a565b10156106f3576001828154811061069d5761069d610a2e565b9060005260206000200160009054906101000a90046001600160a01b03168585815181106106cd576106cd610a2e565b6001600160a01b0390921660209283029190910190910152836106ef81610ac3565b9450505b50806106fe81610ac3565b9150506105d7565b5060008267ffffffffffffffff81111561072257610722610a89565b60405190808252806020026020018201604052801561074b578160200160208202803683370190505b50905060005b838110156107af5784818151811061076b5761076b610a2e565b602002602001015182828151811061078557610785610a2e565b6001600160a01b0390921660209283029190910190910152806107a781610ac3565b915050610751565b50949350505050565b805160005b818110156108b8578060006107d3826001610adc565b90505b8381101561082e578482815181106107f0576107f0610a2e565b602002602001015185828151811061080a5761080a610a2e565b6020026020010151101561081c578091505b8061082681610ac3565b9150506107d6565b508181146108a55783818151811061084857610848610a2e565b602002602001015184838151811061086257610862610a2e565b602002602001015185848151811061087c5761087c610a2e565b6020026020010186848151811061089557610895610a2e565b6020908102919091010191909152525b50806108b081610ac3565b9150506107bd565b505050565b80516000908082036108e25760405163521299a960e01b815260040160405180910390fd5b6108ed600282610b05565b600003610966576002836109018284610b19565b8151811061091157610911610a2e565b60200260200101518460016002856109299190610b19565b6109339190610a5a565b8151811061094357610943610a2e565b60200260200101516109559190610adc565b61095f9190610b19565b9392505050565b82610972600283610b19565b8151811061098257610982610a2e565b6020026020010151915050919050565b6101fd80610b2e83390190565b6000602082840312156109b157600080fd5b5035919050565b6000602082840312156109ca57600080fd5b81356001600160a01b038116811461095f57600080fd5b6020808252825182820181905260009190848201906040850190845b81811015610a225783516001600160a01b0316835292840192918401916001016109fd565b50909695505050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b81810381811115610a6d57610a6d610a44565b92915050565b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60008060408385031215610ab257600080fd5b505080516020909101519092909150565b600060018201610ad557610ad5610a44565b5060010190565b80820180821115610a6d57610a6d610a44565b634e487b7160e01b600052601260045260246000fd5b600082610b1457610b14610aef565b500690565b600082610b2857610b28610aef565b50049056fe608060405234801561001057600080fd5b506040516101fd3803806101fd83398101604081905261002f91610054565b600280546001600160a01b0319166001600160a01b0392909216919091179055610084565b60006020828403121561006657600080fd5b81516001600160a01b038116811461007d57600080fd5b9392505050565b61016a806100936000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80638da5cb5b1461005c57806391b7f5ed1461008c57806398d5fdca146100a1578063a035b1fe146100bc578063b80777ea146100d3575b600080fd5b60025461006f906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b61009f61009a36600461011b565b6100dc565b005b60005460015460408051928352602083019190915201610083565b6100c560005481565b604051908152602001610083565b6100c560015481565b6000819055426001556040518181527f66cbca4f3c64fecf1dcb9ce094abcf7f68c3450a1d4e3a8e917dd621edb4ebe09060200160405180910390a150565b60006020828403121561012d57600080fd5b503591905056fea26469706673582212207bce08ed1ca473e0dddb95384c49cc6f88540c7565db18724ec724cf923ea9a064736f6c63430008140033a26469706673582212204e374c48e5fc716aaca167c543b13ea08d2c65fe57957d69e3d79b85476514d764736f6c63430008140033",
"devdoc": {
"kind": "dev",
"methods": {
"addOracle(address)": {
"details": "Creates a new SimpleOracle instance and adds it to the oracles array.",
"params": {
"_owner": "The address that will own the newly created oracle and can update its price"
}
},
"getActiveOracleNodes()": {
"details": "Iterates through all oracles and filters those with recent timestamps (within STALE_DATA_WINDOW). Uses a temporary array to collect active nodes, then creates a right-sized return array for gas optimization.",
"returns": {
"_0": "An array of addresses representing the currently active oracle contracts"
}
},
"getPrice()": {
"details": "Filters oracles with timestamps older than STALE_DATA_WINDOW, then calculates median of remaining valid prices. Uses StatisticsUtils for sorting and median calculation.",
"returns": {
"_0": "The median price from all active oracles"
}
},
"removeOracle(uint256)": {
"details": "Uses swap-and-pop pattern for gas-efficient removal. Order is not preserved. Reverts with IndexOutOfBounds, if the provided index is >= oracles.length.",
"params": {
"index": "The index of the oracle to remove from the oracles array"
}
}
},
"version": 1
},
"userdoc": {
"errors": {
"EmptyArray()": [
{
"notice": "Errors //////"
}
],
"OnlyOwner()": [
{
"notice": "Errors //////"
}
]
},
"events": {
"OracleAdded(address,address)": {
"notice": "Events /////"
}
},
"kind": "user",
"methods": {
"addOracle(address)": {
"notice": "Adds a new oracle to the whitelist by deploying a SimpleOracle contract (only contract owner)"
},
"constructor": {
"notice": "Constructor ///"
},
"getActiveOracleNodes()": {
"notice": "Returns the addresses of all oracles that have updated their price within the last STALE_DATA_WINDOW"
},
"getPrice()": {
"notice": "Returns the aggregated price from all active oracles using median calculation"
},
"owner()": {
"notice": "State Variables //"
},
"removeOracle(uint256)": {
"notice": "Removes an oracle from the whitelist by its array index (only contract owner)"
}
},
"version": 1
},
"storageLayout": {
"storage": [
{
"astId": 87,
"contract": "contracts/00_Whitelist/WhitelistOracle.sol:WhitelistOracle",
"label": "owner",
"offset": 0,
"slot": "0",
"type": "t_address"
},
{
"astId": 91,
"contract": "contracts/00_Whitelist/WhitelistOracle.sol:WhitelistOracle",
"label": "oracles",
"offset": 0,
"slot": "1",
"type": "t_array(t_contract(SimpleOracle)68)dyn_storage"
}
],
"types": {
"t_address": {
"encoding": "inplace",
"label": "address",
"numberOfBytes": "20"
},
"t_array(t_contract(SimpleOracle)68)dyn_storage": {
"base": "t_contract(SimpleOracle)68",
"encoding": "dynamic_array",
"label": "contract SimpleOracle[]",
"numberOfBytes": "32"
},
"t_contract(SimpleOracle)68": {
"encoding": "inplace",
"label": "contract SimpleOracle",
"numberOfBytes": "20"
}
}
}
}