Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
68 changes: 67 additions & 1 deletion contracts/Comptroller/Diamond/facets/PolicyFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity 0.5.16;

import { VToken } from "../../../Tokens/VTokens/VToken.sol";
import { IPolicyFacet } from "../interfaces/IPolicyFacet.sol";

import { IKeyringChecker } from "../../../KeyringChecker/IKeyringChecker.sol";
import { XVSRewardsHelper } from "./XVSRewardsHelper.sol";

/**
Expand All @@ -14,12 +14,31 @@ import { XVSRewardsHelper } from "./XVSRewardsHelper.sol";
* @notice This facet contract contains all the external pre-hook functions related to vToken
*/
contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
/// @notice The address of the Keyring contract.
/// @dev This could have been immutable, but not possible in upgradeable contracts.
/// @dev Consumes one storage slot.
IKeyringChecker public keyringChecker;

/// @notice The policyId to use with the Keyring contract.
/// @dev This could have been immutable, but not possible in upgradeable contracts.
/// @dev Consumes one storage slot.
uint32 public keyringPolicyId;

/// @notice Whether the keyring guard is enabled.
bool public keyringGuardEnabled;

/// @notice Emitted when a new borrow-side XVS speed is calculated for a market
event VenusBorrowSpeedUpdated(VToken indexed vToken, uint256 newSpeed);

/// @notice Emitted when a new supply-side XVS speed is calculated for a market
event VenusSupplySpeedUpdated(VToken indexed vToken, uint256 newSpeed);

/// @notice Emitted when the keyring configuration is updated.
event KeyringConfigurationUpdated(address keyringChecker, uint32 keyringPolicyId);

/// @notice Emitted when the keyring guard is enabled.
event KeyringGuardEnabled(bool enabled);

/**
* @notice Checks if the account should be allowed to mint tokens in the given market
* @param vToken The market to verify the mint against
Expand All @@ -28,6 +47,8 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
* @return 0 if the mint is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
*/
function mintAllowed(address vToken, address minter, uint256 mintAmount) external returns (uint256) {
ensureUserAllowed(minter);

// Pausing is a very serious situation - we revert to sound the alarms
checkProtocolPauseState();
checkActionPauseState(vToken, Action.MINT);
Expand Down Expand Up @@ -57,6 +78,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
*/
// solhint-disable-next-line no-unused-vars
function mintVerify(address vToken, address minter, uint256 actualMintAmount, uint256 mintTokens) external {
ensureUserAllowed(minter);
if (address(prime) != address(0)) {
prime.accrueInterestAndUpdateScore(minter, vToken);
}
Expand All @@ -70,6 +92,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
* @return 0 if the redeem is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
*/
function redeemAllowed(address vToken, address redeemer, uint256 redeemTokens) external returns (uint256) {
ensureUserAllowed(redeemer);
checkProtocolPauseState();
checkActionPauseState(vToken, Action.REDEEM);

Expand All @@ -93,6 +116,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
* @param redeemTokens The number of tokens being redeemed
*/
function redeemVerify(address vToken, address redeemer, uint256 redeemAmount, uint256 redeemTokens) external {
ensureUserAllowed(redeemer);
require(redeemTokens != 0 || redeemAmount == 0, "redeemTokens zero");
if (address(prime) != address(0)) {
prime.accrueInterestAndUpdateScore(redeemer, vToken);
Expand All @@ -107,6 +131,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
* @return 0 if the borrow is allowed, otherwise a semi-opaque error code (See ErrorReporter.sol)
*/
function borrowAllowed(address vToken, address borrower, uint256 borrowAmount) external returns (uint256) {
ensureUserAllowed(borrower);
// Pausing is a very serious situation - we revert to sound the alarms
checkProtocolPauseState();
checkActionPauseState(vToken, Action.BORROW);
Expand Down Expand Up @@ -162,6 +187,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
*/
// solhint-disable-next-line no-unused-vars
function borrowVerify(address vToken, address borrower, uint256 borrowAmount) external {
ensureUserAllowed(borrower);
if (address(prime) != address(0)) {
prime.accrueInterestAndUpdateScore(borrower, vToken);
}
Expand All @@ -181,6 +207,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
address borrower,
uint256 repayAmount // solhint-disable-line no-unused-vars
) external returns (uint256) {
ensureUserAllowed(payer);
checkProtocolPauseState();
checkActionPauseState(vToken, Action.REPAY);
ensureListed(markets[vToken]);
Expand All @@ -207,6 +234,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
uint256 actualRepayAmount, // solhint-disable-line no-unused-vars
uint256 borrowerIndex // solhint-disable-line no-unused-vars
) external {
ensureUserAllowed(payer);
if (address(prime) != address(0)) {
prime.accrueInterestAndUpdateScore(borrower, vToken);
}
Expand All @@ -227,6 +255,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
address borrower,
uint256 repayAmount
) external view returns (uint256) {
ensureUserAllowed(liquidator);
checkProtocolPauseState();

// if we want to pause liquidating to vTokenCollateral, we should pause seizing
Expand Down Expand Up @@ -288,6 +317,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
uint256 actualRepayAmount, // solhint-disable-line no-unused-vars
uint256 seizeTokens // solhint-disable-line no-unused-vars
) external {
ensureUserAllowed(liquidator);
if (address(prime) != address(0)) {
prime.accrueInterestAndUpdateScore(borrower, vTokenBorrowed);
prime.accrueInterestAndUpdateScore(liquidator, vTokenBorrowed);
Expand All @@ -309,6 +339,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
address borrower,
uint256 seizeTokens // solhint-disable-line no-unused-vars
) external returns (uint256) {
ensureUserAllowed(liquidator);
// Pausing is a very serious situation - we revert to sound the alarms
checkProtocolPauseState();
checkActionPauseState(vTokenCollateral, Action.SEIZE);
Expand Down Expand Up @@ -353,6 +384,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
address borrower,
uint256 seizeTokens // solhint-disable-line no-unused-vars
) external {
ensureUserAllowed(liquidator);
if (address(prime) != address(0)) {
prime.accrueInterestAndUpdateScore(borrower, vTokenCollateral);
prime.accrueInterestAndUpdateScore(liquidator, vTokenCollateral);
Expand All @@ -373,6 +405,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
address dst,
uint256 transferTokens
) external returns (uint256) {
ensureUserAllowed(dst);
// Pausing is a very serious situation - we revert to sound the alarms
checkProtocolPauseState();
checkActionPauseState(vToken, Action.TRANSFER);
Expand Down Expand Up @@ -401,6 +434,7 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
*/
// solhint-disable-next-line no-unused-vars
function transferVerify(address vToken, address src, address dst, uint256 transferTokens) external {
ensureUserAllowed(dst);
if (address(prime) != address(0)) {
prime.accrueInterestAndUpdateScore(src, vToken);
prime.accrueInterestAndUpdateScore(dst, vToken);
Expand Down Expand Up @@ -499,4 +533,36 @@ contract PolicyFacet is IPolicyFacet, XVSRewardsHelper {
emit VenusBorrowSpeedUpdated(vToken, borrowSpeed);
}
}
/// @notice Sets the keyring configuration.
/// @param _keyringChecker The address of the keyring checker.
/// @param _keyringPolicyId The policy id of the keyring.
function setKeyringConfiguration(address _keyringChecker, uint32 _keyringPolicyId) public {
ensureAdmin(msg.sender);
if (address(_keyringChecker) == address(0) || _keyringPolicyId == 0) {
revert InvalidKeyringConfiguration(address(_keyringChecker), _keyringPolicyId);
}
keyringChecker = IKeyringChecker(_keyringChecker);
keyringPolicyId = _keyringPolicyId;
emit KeyringConfigurationUpdated(address(_keyringChecker), _keyringPolicyId);
}

/// @notice Enables or disables the keyring guard.
/// @param _enabled Whether to enable or disable the keyring guard.
function enableKeyringGuard(bool _enabled) public {
ensureAdmin(msg.sender);
keyringGuardEnabled = _enabled;
emit KeyringGuardEnabled(_enabled);
}

/// @notice Checks if the user satisfies the policy.
/// @param _entity The address of the entity to check.
/// @return result True if the user satisfies the policy, false otherwise.
function isUserAllowed(address _entity) public view returns (bool) {
return !keyringGuardEnabled || keyringChecker.checkCredential(keyringPolicyId, _entity);
}

/// @notice Ensures that the user satisfies the policy.
function ensureUserAllowed(address _entity) public view {
require(isUserAllowed(_entity), "User does not have Keyring credential");
}
}
15 changes: 15 additions & 0 deletions contracts/KeyringChecker/IKeyringChecker.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT

pragma solidity =0.8.19;

/// @title Keyring Checker Interface
/// @notice Interface for a contract that checks credentials against a Keyring contract.
interface IKeyringChecker {
/**
* @notice Checks if an entity has a valid credential and supports legacy interface.
* @param policyId The ID of the policy.
* @param entity The address of the entity to check.
* @return True if the entity has a valid credential, false otherwise.
*/
function checkCredential(uint256 policyId, address entity) external view returns (bool);
}
27 changes: 27 additions & 0 deletions contracts/KeyringChecker/mocks/MockedKeyringChecker.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT

pragma solidity =0.8.19;

import { IKeyringChecker } from "../IKeyringChecker.sol";

/// @title Mocked Keyring Checker
/// @notice A mock implementation of IKeyringChecker for testing purposes
contract MockedKeyringChecker is IKeyringChecker {
/// @notice Whether to allow the user or not.
bool public allow = false;

/// @notice Sets the allow flag.
/// @param _allow Whether to allow the user or not.
function setAllow(bool _allow) external {
allow = _allow;
}

/// @notice Checks if the user satisfies the policy.
/// @param policyId The policy ID to check against (unused in mock).
/// @param entity The address to check.
/// @return result True if the user satisfies the policy, false otherwise.
/* solhint-disable-next-line no-unused-vars */
function checkCredential(uint256 policyId, address entity) external view returns (bool) {
return allow;
}
}