Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hypernative security oracle #654

Merged
merged 28 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3ab2fc6
feat: contract changes
rhlsthrm Oct 1, 2024
41776fd
feat: secuirty
rhlsthrm Oct 1, 2024
a07d6ef
feat: test
rhlsthrm Oct 2, 2024
91f2fba
Merge branch 'development' into feat/hypernative-security-oracle
rhlsthrm Oct 3, 2024
c23b8dc
Merge branch 'development' into feat/hypernative-security-oracle
rhlsthrm Oct 4, 2024
7df53db
fix: restructure oracle
rhlsthrm Oct 4, 2024
ad4527f
fix: registry
rhlsthrm Oct 4, 2024
0e0d798
feat: deploy to virtual testnet
rhlsthrm Oct 4, 2024
e90ef8f
feat: upgrade markets
rhlsthrm Oct 4, 2024
8eb2ad9
Merge branch 'development' into feat/hypernative-security-oracle
rhlsthrm Oct 7, 2024
266a8ca
feat: task
rhlsthrm Oct 7, 2024
65fbed9
Merge branch 'development' into feat/hypernative-security-oracle
rhlsthrm Oct 17, 2024
08d116e
feat: hypernative tasks
rhlsthrm Oct 18, 2024
30dfc25
feat: hypernative
rhlsthrm Oct 21, 2024
e2ebfd0
Merge branch 'development' into feat/hypernative-security-oracle
rhlsthrm Oct 21, 2024
fb752ce
Merge branch 'development' into feat/hypernative-security-oracle
rhlsthrm Oct 21, 2024
3eec880
fix: restructure oracle
rhlsthrm Oct 22, 2024
bc1194f
feat: deployments
rhlsthrm Oct 22, 2024
2d0605a
Merge branch 'development' into feat/hypernative-security-oracle
rhlsthrm Oct 23, 2024
35a8ee5
feat: hypernative integration
rhlsthrm Oct 23, 2024
3309498
feat: hypernative
rhlsthrm Oct 23, 2024
8bb3909
Merge branch 'development' into feat/hypernative-security-oracle
rhlsthrm Oct 28, 2024
9d5cece
feat: deploy
rhlsthrm Oct 28, 2024
285f52e
Merge branch 'development' into feat/hypernative-security-oracle
rhlsthrm Oct 29, 2024
34c2f10
feat: deployments
rhlsthrm Oct 29, 2024
830a0ca
feat: deployment
rhlsthrm Oct 29, 2024
54c3139
Merge branch 'development' into feat/hypernative-security-oracle
rhlsthrm Dec 2, 2024
ffb1458
feat: set oracle
rhlsthrm Dec 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions packages/contracts/contracts/compound/CToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@ import { EIP20Interface } from "./EIP20Interface.sol";
import { InterestRateModel } from "./InterestRateModel.sol";
import { ComptrollerV3Storage } from "./ComptrollerStorage.sol";
import { IFeeDistributor } from "./IFeeDistributor.sol";
import { CTokenOracleProtected } from "./CTokenOracleProtected.sol";

import { DiamondExtension, LibDiamond } from "../ionic/DiamondExtension.sol";
import { PoolLens } from "../PoolLens.sol";
import { IonicUniV3Liquidator } from "../IonicUniV3Liquidator.sol";
import { IHypernativeOracle } from "../external/hypernative/interfaces/IHypernativeOracle.sol";

/**
* @title Compound's CErc20 Contract
* @notice CTokens which wrap an EIP-20 underlying
* @dev This contract should not to be deployed on its own; instead, deploy `CErc20Delegator` (proxy contract) and `CErc20Delegate` (logic/implementation contract).
* @author Compound
*/
abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Exponential, DiamondExtension {
abstract contract CErc20 is CTokenOracleProtected, CTokenSecondExtensionBase, TokenErrorReporter, Exponential, DiamondExtension {
modifier isAuthorized() {
require(
IFeeDistributor(ionicAdmin).canCall(address(comptroller), msg.sender, address(this), msg.sig),
Expand Down Expand Up @@ -69,7 +72,7 @@ abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Expon
* @param mintAmount The amount of the underlying asset to supply
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function mint(uint256 mintAmount) external override isAuthorized returns (uint256) {
function mint(uint256 mintAmount) external override isAuthorized onlyOracleApprovedAllowEOA returns (uint256) {
(uint256 err, ) = mintInternal(mintAmount);
return err;
}
Expand All @@ -80,7 +83,7 @@ abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Expon
* @param redeemTokens The number of cTokens to redeem into underlying
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeem(uint256 redeemTokens) external override isAuthorized returns (uint256) {
function redeem(uint256 redeemTokens) external override isAuthorized onlyOracleApprovedAllowEOA returns (uint256) {
return redeemInternal(redeemTokens);
}

Expand All @@ -90,7 +93,7 @@ abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Expon
* @param redeemAmount The amount of underlying to redeem
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function redeemUnderlying(uint256 redeemAmount) external override isAuthorized returns (uint256) {
function redeemUnderlying(uint256 redeemAmount) external override isAuthorized onlyOracleApprovedAllowEOA returns (uint256) {
return redeemUnderlyingInternal(redeemAmount);
}

Expand All @@ -99,7 +102,7 @@ abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Expon
* @param borrowAmount The amount of the underlying asset to borrow
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function borrow(uint256 borrowAmount) external override isAuthorized returns (uint256) {
function borrow(uint256 borrowAmount) external override isAuthorized onlyOracleApprovedAllowEOA returns (uint256) {
return borrowInternal(borrowAmount);
}

Expand All @@ -108,7 +111,7 @@ abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Expon
* @param repayAmount The amount to repay
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function repayBorrow(uint256 repayAmount) external override isAuthorized returns (uint256) {
function repayBorrow(uint256 repayAmount) external override isAuthorized onlyOracleApprovedAllowEOA returns (uint256) {
(uint256 err, ) = repayBorrowInternal(repayAmount);
return err;
}
Expand All @@ -119,7 +122,7 @@ abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Expon
* @param repayAmount The amount to repay
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function repayBorrowBehalf(address borrower, uint256 repayAmount) external override isAuthorized returns (uint256) {
function repayBorrowBehalf(address borrower, uint256 repayAmount) external override isAuthorized onlyOracleApprovedAllowEOA returns (uint256) {
(uint256 err, ) = repayBorrowBehalfInternal(borrower, repayAmount);
return err;
}
Expand All @@ -136,7 +139,7 @@ abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Expon
address borrower,
uint256 repayAmount,
address cTokenCollateral
) external override isAuthorized isMinHFThresholdExceeded(borrower) returns (uint256) {
) external override isAuthorized onlyOracleApprovedAllowEOA isMinHFThresholdExceeded(borrower) returns (uint256) {
(uint256 err, ) = liquidateBorrowInternal(borrower, repayAmount, cTokenCollateral);
return err;
}
Expand All @@ -162,7 +165,7 @@ abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Expon
address liquidator,
address borrower,
uint256 seizeTokens
) external override nonReentrant(true) returns (uint256) {
) external override nonReentrant(true) onlyOracleApprovedAllowEOA returns (uint256) {
return seizeInternal(msg.sender, liquidator, borrower, seizeTokens);
}

Expand All @@ -181,7 +184,7 @@ abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Expon
* @param withdrawAmount Amount of fees to withdraw
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _withdrawIonicFees(uint256 withdrawAmount) external override nonReentrant(false) returns (uint256) {
function _withdrawIonicFees(uint256 withdrawAmount) external override nonReentrant(false) onlyOracleApproved returns (uint256) {
asCTokenExtension().accrueInterest();

if (accrualBlockNumber != block.number) {
Expand Down Expand Up @@ -214,7 +217,7 @@ abstract contract CErc20 is CTokenSecondExtensionBase, TokenErrorReporter, Expon
* @param withdrawAmount Amount of fees to withdraw
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _withdrawAdminFees(uint256 withdrawAmount) external override nonReentrant(false) returns (uint256) {
function _withdrawAdminFees(uint256 withdrawAmount) external override nonReentrant(false) onlyOracleApproved returns (uint256) {
asCTokenExtension().accrueInterest();

if (accrualBlockNumber != block.number) {
Expand Down
27 changes: 20 additions & 7 deletions packages/contracts/contracts/compound/CTokenFirstExtension.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import { TokenErrorReporter } from "./ErrorReporter.sol";
import { Exponential } from "./Exponential.sol";
import { InterestRateModel } from "./InterestRateModel.sol";
import { IFeeDistributor } from "./IFeeDistributor.sol";
import { Multicall } from "../utils/Multicall.sol";
import { CTokenOracleProtected } from "./CTokenOracleProtected.sol";

import { IERC20, SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import { Multicall } from "../utils/Multicall.sol";
import { AddressesProvider } from "../ionic/AddressesProvider.sol";
import { IHypernativeOracle } from "../external/hypernative/interfaces/IHypernativeOracle.sol";

contract CTokenFirstExtension is
CTokenOracleProtected,
CErc20FirstExtensionBase,
TokenErrorReporter,
Exponential,
Expand Down Expand Up @@ -147,7 +150,10 @@ contract CTokenFirstExtension is
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transfer(address dst, uint256 amount) public override nonReentrant(false) isAuthorized returns (bool) {
function transfer(
address dst,
uint256 amount
) public override nonReentrant(false) isAuthorized onlyOracleApprovedAllowEOA returns (bool) {
return transferTokens(msg.sender, msg.sender, dst, amount) == uint256(Error.NO_ERROR);
}

Expand All @@ -162,7 +168,7 @@ contract CTokenFirstExtension is
address src,
address dst,
uint256 amount
) public override nonReentrant(false) isAuthorized returns (bool) {
) public override nonReentrant(false) isAuthorized onlyOracleApprovedAllowEOA returns (bool) {
return transferTokens(msg.sender, src, dst, amount) == uint256(Error.NO_ERROR);
}

Expand All @@ -174,7 +180,10 @@ contract CTokenFirstExtension is
* @param amount The number of tokens that are approved (-1 means infinite)
* @return Whether or not the approval succeeded
*/
function approve(address spender, uint256 amount) public override isAuthorized returns (bool) {
function approve(
address spender,
uint256 amount
) public override isAuthorized onlyOracleApprovedAllowEOA returns (bool) {
address src = msg.sender;
transferAllowances[src][spender] = amount;
emit Approval(src, spender, amount);
Expand Down Expand Up @@ -229,7 +238,9 @@ contract CTokenFirstExtension is
* @dev Admin function to accrue interest and set a new reserve factor
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setReserveFactor(uint256 newReserveFactorMantissa) public override nonReentrant(false) returns (uint256) {
function _setReserveFactor(
uint256 newReserveFactorMantissa
) public override nonReentrant(false) returns (uint256) {
accrueInterest();
// Check caller is admin
if (!hasAdminRights()) {
Expand Down Expand Up @@ -259,7 +270,9 @@ contract CTokenFirstExtension is
* @dev Admin function to accrue interest and set a new admin fee
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _setAdminFee(uint256 newAdminFeeMantissa) public override nonReentrant(false) returns (uint256) {
function _setAdminFee(
uint256 newAdminFeeMantissa
) public override nonReentrant(false) returns (uint256) {
accrueInterest();
// Verify market's block number equals current block number
if (accrualBlockNumber != block.number) {
Expand Down Expand Up @@ -638,7 +651,7 @@ contract CTokenFirstExtension is
return balance;
}

function flash(uint256 amount, bytes calldata data) public override isAuthorized {
function flash(uint256 amount, bytes calldata data) public override isAuthorized onlyOracleApprovedAllowEOA {
accrueInterest();

totalBorrows += amount;
Expand Down
36 changes: 36 additions & 0 deletions packages/contracts/contracts/compound/CTokenOracleProtected.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.22;

import { CErc20Storage } from "./CTokenInterfaces.sol";
import { IHypernativeOracle } from "../external/hypernative/interfaces/IHypernativeOracle.sol";

contract CTokenOracleProtected is CErc20Storage {
error InteractionNotAllowed();

modifier onlyOracleApproved() {
address oracleAddress = ap.getAddress("HYPERNATIVE_ORACLE");
if (oracleAddress == address(0)) {
_;
return;
}
IHypernativeOracle oracle = IHypernativeOracle(oracleAddress);
if (oracle.isBlacklistedContext(msg.sender, tx.origin) || !oracle.isTimeExceeded(msg.sender)) {
revert InteractionNotAllowed();
}
_;
}

modifier onlyOracleApprovedAllowEOA() {
address oracleAddress = ap.getAddress("HYPERNATIVE_ORACLE");
if (oracleAddress == address(0)) {
_;
return;
}

IHypernativeOracle oracle = IHypernativeOracle(oracleAddress);
if (oracle.isBlacklistedAccount(msg.sender) || msg.sender != tx.origin) {
revert InteractionNotAllowed();
}
_;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

interface IHypernativeOracle {
function register(address account) external;
function registerStrict(address account) external;
function isBlacklistedAccount(address account) external view returns (bool);
function isBlacklistedContext(address sender, address origin) external view returns (bool);
function isTimeExceeded(address account) external view returns (bool);
}
80 changes: 80 additions & 0 deletions packages/contracts/contracts/security/OracleRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import { IHypernativeOracle } from "../external/hypernative/interfaces/IHypernativeOracle.sol";
import { Ownable2Step } from "@openzeppelin/contracts/access/Ownable2Step.sol";

contract OracleRegistry is Ownable2Step {
bytes32 private constant HYPERNATIVE_ORACLE_STORAGE_SLOT =
bytes32(uint256(keccak256("eip1967.hypernative.oracle")) - 1);
bytes32 private constant HYPERNATIVE_MODE_STORAGE_SLOT =
bytes32(uint256(keccak256("eip1967.hypernative.is_strict_mode")) - 1);

event OracleAdminChanged(address indexed previousAdmin, address indexed newAdmin);
event OracleAddressChanged(address indexed previousOracle, address indexed newOracle);

constructor() Ownable2Step() {}

function oracleRegister(address _account) public {
address oracleAddress = _getAddressBySlot(HYPERNATIVE_ORACLE_STORAGE_SLOT);
IHypernativeOracle oracle = IHypernativeOracle(oracleAddress);
if (hypernativeOracleIsStrictMode()) {
oracle.registerStrict(_account);
} else {
oracle.register(_account);
}
}

function setOracle(address _oracle) public onlyOwner {
_setOracle(_oracle);
}

function setIsStrictMode(bool _mode) public onlyOwner {
_setIsStrictMode(_mode);
}

function hypernativeOracleIsStrictMode() public view returns (bool) {
return _getValueBySlot(HYPERNATIVE_MODE_STORAGE_SLOT) == 1;
}

function hypernativeOracle() public view returns (address) {
return _getAddressBySlot(HYPERNATIVE_ORACLE_STORAGE_SLOT);
}

/**
* @dev Admin only function, sets new oracle admin. set to address(0) to revoke oracle
*/
function _setOracle(address _oracle) internal {
address oldOracle = hypernativeOracle();
_setAddressBySlot(HYPERNATIVE_ORACLE_STORAGE_SLOT, _oracle);
emit OracleAddressChanged(oldOracle, _oracle);
}

function _setIsStrictMode(bool _mode) internal {
_setValueBySlot(HYPERNATIVE_MODE_STORAGE_SLOT, _mode ? 1 : 0);
}

function _setAddressBySlot(bytes32 slot, address newAddress) internal {
assembly {
sstore(slot, newAddress)
}
}

function _setValueBySlot(bytes32 _slot, uint256 _value) internal {
assembly {
sstore(_slot, _value)
}
}

function _getAddressBySlot(bytes32 slot) internal view returns (address addr) {
assembly {
addr := sload(slot)
}
}

function _getValueBySlot(bytes32 _slot) internal view returns (uint256 _value) {
assembly {
_value := sload(_slot)
}
}
}
Loading
Loading