@ubk-labs/ubk-oracle 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,7 @@ import "@openzeppelin/contracts/interfaces/IERC4626.sol";
7
7
  import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
8
8
 
9
9
  import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
10
+ import "@ubk-labs/ubk-commons/contracts/abstract/UBKDecimalsBounded.sol";
10
11
 
11
12
  import "../../interfaces/IUBKOracle.sol";
12
13
  import "../errors/UBKOracleErrors.sol";
@@ -39,7 +40,7 @@ import "../constants/UBKOracleConstants.sol";
39
40
  * - UI / Subgraphs can use `isPriceFresh()` and `getPriceAge()` for safety checks.
40
41
  *
41
42
  */
42
- contract UBKOracle is IUBKOracle, Ownable {
43
+ contract UBKOracle is IUBKOracle, UBKDecimalsBounded, Ownable {
43
44
  // -----------------------------------------------------------------------
44
45
  // Storage
45
46
  // -----------------------------------------------------------------------
@@ -87,10 +88,7 @@ contract UBKOracle is IUBKOracle, Ownable {
87
88
  * @notice Deploys the Oracle contract.
88
89
  * @param _owner The address to assign as the owner (governance or deployer).
89
90
  */
90
- constructor(address _owner) Ownable(_owner) {
91
- if (_owner == address(0))
92
- revert ZeroAddress("UBKOracle::constructor", "owner");
93
- }
91
+ constructor(address _owner) Ownable(_owner) {}
94
92
 
95
93
  /// @notice Ensures oracle is not paused.
96
94
  modifier whenNotPaused() {
@@ -240,9 +238,7 @@ contract UBKOracle is IUBKOracle, Ownable {
240
238
  * @dev Ensures decimals ≤ 18 and feed returns a nonzero updatedAt value.
241
239
  */
242
240
  function setChainlinkFeed(address token, address feed) external onlyOwner {
243
- if (token == address(0) || feed == address(0))
244
- revert ZeroAddress("UBKOracle::setChainlinkFeed", "input");
245
- if (feed.code.length == 0) revert InvalidFeedContract(feed);
241
+ _validateChainlinkFeed(token, feed);
246
242
 
247
243
  AggregatorV3Interface agg = AggregatorV3Interface(feed);
248
244
  uint8 decimals = agg.decimals();
@@ -276,11 +272,7 @@ contract UBKOracle is IUBKOracle, Ownable {
276
272
  address vault,
277
273
  address underlying
278
274
  ) external onlyOwner {
279
- if (vault == address(0) || underlying == address(0))
280
- revert ZeroAddress("UBKOracle::setERC4626Vault", "input");
281
- try IERC4626(vault).asset() returns (address) {} catch {
282
- revert InvalidERC4626Vault(vault);
283
- }
275
+ _validateERC4626Vault(vault, underlying);
284
276
  erc4626Underlying[vault] = underlying;
285
277
  _addSupportedToken(vault);
286
278
  emit ERC4626Registered(vault, underlying);
@@ -612,4 +604,52 @@ contract UBKOracle is IUBKOracle, Ownable {
612
604
  emit TokenSupportAdded(token);
613
605
  }
614
606
  }
607
+
608
+ /**
609
+ * @notice Validates assets and their associated Chainlink feeds before mutating system state.
610
+ * @param token Asset token address.
611
+ * @param feed Chainlink AggregatorV3 feed address.
612
+ * @dev Ensures decimals ≤ 18 and feed returns a nonzero updatedAt value.
613
+ */
614
+ function _validateChainlinkFeed(address token, address feed) internal view {
615
+ if (token == address(0))
616
+ revert ZeroAddress("UBKOracle::setChainlinkFeed", "token");
617
+ if (feed == address(0))
618
+ revert ZeroAddress("UBKOracle::setChainlinkFeed", "feed");
619
+ if (feed.code.length == 0) revert InvalidFeedContract(feed);
620
+ _validateTokenDecimals(token);
621
+ }
622
+
623
+ /**
624
+ * @notice Validates input parameters before setting an ERc 4626 vault.
625
+ * @dev Ensures decimals for vault and underlying assets are equal, and bounded by global invariants.
626
+ * @param vault ERC-4626 asset.
627
+ * @param underlying ERC-20 asset.
628
+ */
629
+ function _validateERC4626Vault(
630
+ address vault,
631
+ address underlying
632
+ ) internal view {
633
+ if (vault == address(0))
634
+ revert ZeroAddress("UBKOracle::_validateERC4626Vault", "vault");
635
+ if (underlying == address(0)) {
636
+ revert ZeroAddress(
637
+ "UBKOracle::_validateERC4626Vault",
638
+ "underlying"
639
+ );
640
+ }
641
+ try IERC4626(vault).asset() returns (address) {} catch {
642
+ revert InvalidERC4626Vault(vault);
643
+ }
644
+ uint8 vaultDecimals = _validateTokenDecimals(vault); // Must be between [6,18]
645
+ uint8 underlyingDecimals = _validateTokenDecimals(underlying); // Must be between [6,18]
646
+
647
+ if (vaultDecimals != underlyingDecimals) {
648
+ revert ERC4626DecimalsMismatch(
649
+ "UBKOracle::_validateERC4626Vault",
650
+ vault,
651
+ underlying
652
+ );
653
+ }
654
+ }
615
655
  }
@@ -19,3 +19,4 @@ error NoFallbackPrice(address token);
19
19
  error SuspiciousVaultRate(address vault, uint256 rate);
20
20
  error RecursiveResolution(address token);
21
21
  error OraclePaused(address oracle, uint256 timestamp);
22
+ error ERC4626DecimalsMismatch(string functionName, address vault, address underlying);
@@ -0,0 +1,5 @@
1
+ {
2
+ "0.1.7": "0x37814FAA5bd659888380CBa070F098Cc0999A8cA",
3
+ "0.1.8": "0x5d4747d514B529005F4014f26068E1f4Ec47E06B",
4
+ "0.1.9": "0x04B21e27e24Ab71472690C9a09BC7A826d658668"
5
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ubk-labs/ubk-oracle",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Oracle supporting ERC-20 and ERC-4626 assets for use in decentralized financial applications.",
5
5
  "scripts": {
6
6
  "build": "npx hardhat compile",
@@ -20,6 +20,7 @@
20
20
  "files": [
21
21
  "contracts",
22
22
  "interfaces",
23
+ "deployments",
23
24
  "README.md",
24
25
  "LICENSE",
25
26
  "package.json"
@@ -37,6 +38,6 @@
37
38
  },
38
39
  "dependencies": {
39
40
  "@chainlink/contracts": "^0.6.1",
40
- "@ubk-labs/ubk-commons": "^0.1.5"
41
+ "@ubk-labs/ubk-commons": "^0.1.7"
41
42
  }
42
43
  }