diff --git a/contracts/Diamond/facets/RewardFacet.sol b/contracts/Diamond/facets/RewardFacet.sol new file mode 100644 index 000000000..bf79e85cb --- /dev/null +++ b/contracts/Diamond/facets/RewardFacet.sol @@ -0,0 +1,233 @@ +pragma solidity ^0.5.16; + +import "../Oracle/PriceOracle.sol"; +import "../Tokens/VTokens/VToken.sol"; +import "../Utils/ErrorReporter.sol"; +import "../Tokens/XVS/XVS.sol"; +import "../Tokens/VAI/VAI.sol"; +import "../Governance/IAccessControlManager.sol"; + +contract RewardFacet is ComptrollerErrorReporter, ExponentialNoError { + AppStorage internal s; + /// @notice Emitted when Venus is granted by admin + event VenusGranted(address recipient, uint amount); + + /// @notice Emitted when XVS is distributed to VAI Vault + event DistributedVAIVaultVenus(uint amount); + + /** + * @notice Claim all the xvs accrued by holder in all markets and VAI + * @param holder The address to claim XVS for + */ + function claimVenus(address holder) public { + return claimVenus(holder, allMarkets); + } + + /** + * @notice Claim all the xvs accrued by holder in the specified markets + * @param holder The address to claim XVS for + * @param vTokens The list of markets to claim XVS in + */ + function claimVenus(address holder, VToken[] memory vTokens) public { + address[] memory holders = new address[](1); + holders[0] = holder; + claimVenus(holders, vTokens, true, true); + } + + /** + * @notice Claim all xvs accrued by the holders + * @param holders The addresses to claim XVS for + * @param vTokens The list of markets to claim XVS in + * @param borrowers Whether or not to claim XVS earned by borrowing + * @param suppliers Whether or not to claim XVS earned by supplying + */ + function claimVenus(address[] memory holders, VToken[] memory vTokens, bool borrowers, bool suppliers) public { + claimVenus(holders, vTokens, borrowers, suppliers, false); + } + + /** + * @notice Claim all the xvs accrued by holder in all markets, a shorthand for `claimVenus` with collateral set to `true` + * @param holder The address to claim XVS for + */ + function claimVenusAsCollateral(address holder) external { + address[] memory holders = new address[](1); + holders[0] = holder; + claimVenus(holders, allMarkets, true, true, true); + } + + /** + * @notice Transfer XVS to the user with user's shortfall considered + * @dev Note: If there is not enough XVS, we do not perform the transfer all. + * @param user The address of the user to transfer XVS to + * @param amount The amount of XVS to (possibly) transfer + * @param shortfall The shortfall of the user + * @param collateral Whether or not we will use user's venus reward as collateral to pay off the debt + * @return The amount of XVS which was NOT transferred to the user + */ + function grantXVSInternal(address user, uint amount, uint shortfall, bool collateral) internal returns (uint) { + // If the user is blacklisted, they can't get XVS rewards + require( + user != 0xEF044206Db68E40520BfA82D45419d498b4bc7Bf && + user != 0x7589dD3355DAE848FDbF75044A3495351655cB1A && + user != 0x33df7a7F6D44307E1e5F3B15975b47515e5524c0 && + user != 0x24e77E5b74B30b026E9996e4bc3329c881e24968, + "Blacklisted" + ); + + XVS xvs = XVS(getXVSAddress()); + + if (amount == 0 || amount > xvs.balanceOf(address(this))) { + return amount; + } + + if (shortfall == 0) { + xvs.transfer(user, amount); + return 0; + } + // If user's bankrupt and doesn't use pending xvs as collateral, don't grant + // anything, otherwise, we will transfer the pending xvs as collateral to + // vXVS token and mint vXVS for the user. + // + // If mintBehalf failed, don't grant any xvs + require(collateral, "bankrupt accounts can only collateralize their pending xvs rewards"); + + xvs.approve(getXVSVTokenAddress(), amount); + require( + VBep20Interface(getXVSVTokenAddress()).mintBehalf(user, amount) == uint(Error.NO_ERROR), + "mint behalf error during collateralize xvs" + ); + + // set venusAccrue[user] to 0 + return 0; + } + + /*** Venus Distribution Admin ***/ + + /** + * @notice Transfer XVS to the recipient + * @dev Note: If there is not enough XVS, we do not perform the transfer all. + * @param recipient The address of the recipient to transfer XVS to + * @param amount The amount of XVS to (possibly) transfer + */ + function _grantXVS(address recipient, uint amount) external { + ensureAdminOr(comptrollerImplementation); + uint amountLeft = grantXVSInternal(recipient, amount, 0, false); + require(amountLeft == 0, "insufficient xvs for grant"); + emit VenusGranted(recipient, amount); + } + + function getBlockNumber() public view returns (uint) { + return block.number; + } + + /** + * @notice Return the address of the XVS token + * @return The address of XVS + */ + function getXVSAddress() public view returns (address) { + return 0xcF6BB5389c92Bdda8a3747Ddb454cB7a64626C63; + } + + /** + * @notice Return the address of the XVS vToken + * @return The address of XVS vToken + */ + function getXVSVTokenAddress() public view returns (address) { + return 0x151B1e2635A717bcDc836ECd6FbB62B674FE3E1D; + } + + /** + * @notice Checks if a certain action is paused on a market + * @param action Action id + * @param market vToken address + */ + function actionPaused(address market, Action action) public view returns (bool) { + return _actionPaused[market][uint(action)]; + } + + /*** VAI functions ***/ + + /** + * @notice Transfer XVS to VAI Vault + */ + function releaseToVault() public { + if (releaseStartBlock == 0 || getBlockNumber() < releaseStartBlock) { + return; + } + + XVS xvs = XVS(getXVSAddress()); + + uint256 xvsBalance = xvs.balanceOf(address(this)); + if (xvsBalance == 0) { + return; + } + + uint256 actualAmount; + uint256 deltaBlocks = sub_(getBlockNumber(), releaseStartBlock); + // releaseAmount = venusVAIVaultRate * deltaBlocks + uint256 _releaseAmount = mul_(venusVAIVaultRate, deltaBlocks); + + if (xvsBalance >= _releaseAmount) { + actualAmount = _releaseAmount; + } else { + actualAmount = xvsBalance; + } + + if (actualAmount < minReleaseAmount) { + return; + } + + s.releaseStartBlock = getBlockNumber(); + + xvs.transfer(vaiVaultAddress, actualAmount); + emit DistributedVAIVaultVenus(actualAmount); + + IVAIVault(vaiVaultAddress).updatePendingRewards(); + } + + /** + * @notice Claim all xvs accrued by the holders + * @param holders The addresses to claim XVS for + * @param vTokens The list of markets to claim XVS in + * @param borrowers Whether or not to claim XVS earned by borrowing + * @param suppliers Whether or not to claim XVS earned by supplying + * @param collateral Whether or not to use XVS earned as collateral, only takes effect when the holder has a shortfall + */ + function claimVenus( + address[] memory holders, + VToken[] memory vTokens, + bool borrowers, + bool suppliers, + bool collateral + ) public { + uint j; + uint256 holdersLength = holders.length; + for (uint i; i < vTokens.length; ++i) { + VToken vToken = vTokens[i]; + ensureListed(markets[address(vToken)]); + if (borrowers) { + Exp memory borrowIndex = Exp({ mantissa: vToken.borrowIndex() }); + updateVenusBorrowIndex(address(vToken), borrowIndex); + for (j = 0; j < holdersLength; ++j) { + distributeBorrowerVenus(address(vToken), holders[j], borrowIndex); + } + } + if (suppliers) { + updateVenusSupplyIndex(address(vToken)); + for (j = 0; j < holdersLength; ++j) { + distributeSupplierVenus(address(vToken), holders[j]); + } + } + } + + for (j = 0; j < holdersLength; ++j) { + address holder = holders[j]; + // If there is a positive shortfall, the XVS reward is accrued, + // but won't be granted to this holder + (, , uint shortfall) = getHypotheticalAccountLiquidityInternal(holder, VToken(0), 0, 0); + venusAccrued[holder] = grantXVSInternal(holder, venusAccrued[holder], shortfall, collateral); + } + } + +} + \ No newline at end of file diff --git a/contracts/Diamond/facets/SetterFacet.sol b/contracts/Diamond/facets/SetterFacet.sol new file mode 100644 index 000000000..26f9cf96e --- /dev/null +++ b/contracts/Diamond/facets/SetterFacet.sol @@ -0,0 +1,447 @@ +pragma solidity ^0.5.16; + +import "../Oracle/PriceOracle.sol"; +import "../Tokens/VTokens/VToken.sol"; +import "../Utils/ErrorReporter.sol"; +import "../Tokens/XVS/XVS.sol"; +import "../Tokens/VAI/VAI.sol"; +import "../Governance/IAccessControlManager.sol"; +import "../libraries/libAccessCheck.sol"; + +contract SetterFacet is ComptrollerErrorReporter, ExponentialNoError{ + AppStorage internal s; + /// @notice Emitted when close factor is changed by admin + event NewCloseFactor(uint oldCloseFactorMantissa, uint newCloseFactorMantissa); + + /// @notice Emitted when a collateral factor is changed by admin + event NewCollateralFactor(VToken vToken, uint oldCollateralFactorMantissa, uint newCollateralFactorMantissa); + + /// @notice Emitted when liquidation incentive is changed by admin + event NewLiquidationIncentive(uint oldLiquidationIncentiveMantissa, uint newLiquidationIncentiveMantissa); + + /// @notice Emitted when price oracle is changed + event NewPriceOracle(PriceOracle oldPriceOracle, PriceOracle newPriceOracle); + + /// @notice Emitted when borrow cap for a vToken is changed + event NewBorrowCap(VToken indexed vToken, uint newBorrowCap); + + /// @notice Emitted when VAIController is changed + event NewVAIController(VAIControllerInterface oldVAIController, VAIControllerInterface newVAIController); + + /// @notice Emitted when VAI mint rate is changed by admin + event NewVAIMintRate(uint oldVAIMintRate, uint newVAIMintRate); + + /// @notice Emitted when protocol state is changed by admin + event ActionProtocolPaused(bool state); + + /// @notice Emitted when treasury guardian is changed + event NewTreasuryGuardian(address oldTreasuryGuardian, address newTreasuryGuardian); + + /// @notice Emitted when treasury address is changed + event NewTreasuryAddress(address oldTreasuryAddress, address newTreasuryAddress); + + /// @notice Emitted when treasury percent is changed + event NewTreasuryPercent(uint oldTreasuryPercent, uint newTreasuryPercent); + + /// @notice Emitted when liquidator adress is changed + event NewLiquidatorContract(address oldLiquidatorContract, address newLiquidatorContract); + + /// @notice Emitted whe ComptrollerLens address is changed + event NewComptrollerLens(address oldComptrollerLens, address newComptrollerLens); + + /// @notice Emitted when supply cap for a vToken is changed + event NewSupplyCap(VToken indexed vToken, uint newSupplyCap); + + /// @notice Emitted when access control address is changed by admin + event NewAccessControl(address oldAccessControlAddress, address newAccessControlAddress); + + /// @notice Emitted when pause guardian is changed + event NewPauseGuardian(address oldPauseGuardian, address newPauseGuardian); + + /// @notice Emitted when an action is paused on a market + event ActionPausedMarket(VToken indexed vToken, Action indexed action, bool pauseState); + + /// @notice Emitted when prime token contract address is changed + event NewPrimeToken(IPrime oldPrimeToken, IPrime newPrimeToken); + + /// @notice Emitted when VAI Vault info is changed + event NewVAIVaultInfo(address vault_, uint releaseStartBlock_, uint releaseInterval_); + + /// @notice Emitted when Venus VAI Vault rate is changed + event NewVenusVAIVaultRate(uint oldVenusVAIVaultRate, uint newVenusVAIVaultRate); + + /** + * @notice Sets a new price oracle for the comptroller + * @dev Admin function to set a new price oracle + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setPriceOracle(PriceOracle newOracle) external returns (uint) { + // Check caller is admin + LibAccessCheck.ensureAdmin(); + LibAccessCheck.ensureNonzeroAddress(address(newOracle)); + + // Track the old oracle for the comptroller + PriceOracle oldOracle = oracle; + + // Set comptroller's oracle to newOracle + s.oracle = newOracle; + + // Emit NewPriceOracle(oldOracle, newOracle) + emit NewPriceOracle(oldOracle, newOracle); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets the closeFactor used when liquidating borrows + * @dev Admin function to set closeFactor + * @param newCloseFactorMantissa New close factor, scaled by 1e18 + * @return uint 0=success, otherwise will revert + */ + function _setCloseFactor(uint newCloseFactorMantissa) external returns (uint) { + // Check caller is admin + ensureAdmin(); + + uint oldCloseFactorMantissa = closeFactorMantissa; + s.closeFactorMantissa = newCloseFactorMantissa; + emit NewCloseFactor(oldCloseFactorMantissa, newCloseFactorMantissa); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets the address of the access control of this contract + * @dev Admin function to set the access control address + * @param newAccessControlAddress New address for the access control + * @return uint 0=success, otherwise will revert + */ + function _setAccessControl(address newAccessControlAddress) external returns (uint) { + // Check caller is admin + ensureAdmin(); + ensureNonzeroAddress(newAccessControlAddress); + + address oldAccessControlAddress = accessControl; + s.accessControl = newAccessControlAddress; + emit NewAccessControl(oldAccessControlAddress, accessControl); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets the collateralFactor for a market + * @dev Restricted function to set per-market collateralFactor + * @param vToken The market to set the factor on + * @param newCollateralFactorMantissa The new collateral factor, scaled by 1e18 + * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) + */ + function _setCollateralFactor(VToken vToken, uint newCollateralFactorMantissa) external returns (uint) { + // Check caller is allowed by access control manager + ensureAllowed("_setCollateralFactor(address,uint256)"); + ensureNonzeroAddress(address(vToken)); + + // Verify market is listed + Market storage market = markets[address(vToken)]; + ensureListed(market); + + Exp memory newCollateralFactorExp = Exp({ mantissa: newCollateralFactorMantissa }); + + // Check collateral factor <= 0.9 + Exp memory highLimit = Exp({ mantissa: collateralFactorMaxMantissa }); + if (lessThanExp(highLimit, newCollateralFactorExp)) { + return fail(Error.INVALID_COLLATERAL_FACTOR, FailureInfo.SET_COLLATERAL_FACTOR_VALIDATION); + } + + // If collateral factor != 0, fail if price == 0 + if (newCollateralFactorMantissa != 0 && oracle.getUnderlyingPrice(vToken) == 0) { + return fail(Error.PRICE_ERROR, FailureInfo.SET_COLLATERAL_FACTOR_WITHOUT_PRICE); + } + + // Set market's collateral factor to new collateral factor, remember old value + uint oldCollateralFactorMantissa = market.collateralFactorMantissa; + market.collateralFactorMantissa = newCollateralFactorMantissa; + + // Emit event with asset, old collateral factor, and new collateral factor + emit NewCollateralFactor(vToken, oldCollateralFactorMantissa, newCollateralFactorMantissa); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Sets liquidationIncentive + * @dev Admin function to set liquidationIncentive + * @param newLiquidationIncentiveMantissa New liquidationIncentive scaled by 1e18 + * @return uint 0=success, otherwise a failure. (See ErrorReporter for details) + */ + function _setLiquidationIncentive(uint newLiquidationIncentiveMantissa) external returns (uint) { + ensureAllowed("_setLiquidationIncentive(uint256)"); + + require(newLiquidationIncentiveMantissa >= 1e18, "incentive must be over 1e18"); + + // Save current value for use in log + uint oldLiquidationIncentiveMantissa = liquidationIncentiveMantissa; + + // Set liquidation incentive to new incentive + liquidationIncentiveMantissa = newLiquidationIncentiveMantissa; + + // Emit event with old incentive, new incentive + emit NewLiquidationIncentive(oldLiquidationIncentiveMantissa, newLiquidationIncentiveMantissa); + + return uint(Error.NO_ERROR); + } + + function _setLiquidatorContract(address newLiquidatorContract_) external { + // Check caller is admin + ensureAdmin(); + address oldLiquidatorContract = liquidatorContract; + liquidatorContract = newLiquidatorContract_; + emit NewLiquidatorContract(oldLiquidatorContract, newLiquidatorContract_); + } + + /** + * @notice Admin function to change the Pause Guardian + * @param newPauseGuardian The address of the new Pause Guardian + * @return uint 0=success, otherwise a failure. (See enum Error for details) + */ + function _setPauseGuardian(address newPauseGuardian) external returns (uint) { + ensureAdmin(); + ensureNonzeroAddress(newPauseGuardian); + + // Save current value for inclusion in log + address oldPauseGuardian = pauseGuardian; + + // Store pauseGuardian with value newPauseGuardian + s.pauseGuardian = newPauseGuardian; + + // Emit NewPauseGuardian(OldPauseGuardian, NewPauseGuardian) + emit NewPauseGuardian(oldPauseGuardian, newPauseGuardian); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Set the given borrow caps for the given vToken markets. Borrowing that brings total borrows to or above borrow cap will revert. + * @dev Access is controled by ACM. A borrow cap of 0 corresponds to unlimited borrowing. + * @param vTokens The addresses of the markets (tokens) to change the borrow caps for + * @param newBorrowCaps The new borrow cap values in underlying to be set. A value of 0 corresponds to unlimited borrowing. + */ + function _setMarketBorrowCaps(VToken[] calldata vTokens, uint[] calldata newBorrowCaps) external { + ensureAllowed("_setMarketBorrowCaps(address[],uint256[])"); + + uint numMarkets = vTokens.length; + uint numBorrowCaps = newBorrowCaps.length; + + require(numMarkets != 0 && numMarkets == numBorrowCaps, "invalid input"); + + for (uint i; i < numMarkets; ++i) { + borrowCaps[address(vTokens[i])] = newBorrowCaps[i]; + emit NewBorrowCap(vTokens[i], newBorrowCaps[i]); + } + } + + /** + * @notice Set the given supply caps for the given vToken markets. Supply that brings total Supply to or above supply cap will revert. + * @dev Admin function to set the supply caps. A supply cap of 0 corresponds to Minting NotAllowed. + * @param vTokens The addresses of the markets (tokens) to change the supply caps for + * @param newSupplyCaps The new supply cap values in underlying to be set. A value of 0 corresponds to Minting NotAllowed. + */ + function _setMarketSupplyCaps(VToken[] calldata vTokens, uint256[] calldata newSupplyCaps) external { + ensureAllowed("_setMarketSupplyCaps(address[],uint256[])"); + + uint numMarkets = vTokens.length; + uint numSupplyCaps = newSupplyCaps.length; + + require(numMarkets != 0 && numMarkets == numSupplyCaps, "invalid input"); + + for (uint i; i < numMarkets; ++i) { + supplyCaps[address(vTokens[i])] = newSupplyCaps[i]; + emit NewSupplyCap(vTokens[i], newSupplyCaps[i]); + } + } + + /** + * @notice Set whole protocol pause/unpause state + */ + function _setProtocolPaused(bool state) external returns (bool) { + ensureAllowed("_setProtocolPaused(bool)"); + + protocolPaused = state; + emit ActionProtocolPaused(state); + return state; + } + + /** + * @notice Pause/unpause certain actions + * @param markets Markets to pause/unpause the actions on + * @param actions List of action ids to pause/unpause + * @param paused The new paused state (true=paused, false=unpaused) + */ + function _setActionsPaused(address[] calldata markets, Action[] calldata actions, bool paused) external { + ensureAllowed("_setActionsPaused(address[],uint256[],bool)"); + + uint256 numMarkets = markets.length; + uint256 numActions = actions.length; + for (uint marketIdx; marketIdx < numMarkets; ++marketIdx) { + for (uint actionIdx; actionIdx < numActions; ++actionIdx) { + setActionPausedInternal(markets[marketIdx], actions[actionIdx], paused); + } + } + } + + /** + * @dev Pause/unpause an action on a market + * @param market Market to pause/unpause the action on + * @param action Action id to pause/unpause + * @param paused The new paused state (true=paused, false=unpaused) + */ + function setActionPausedInternal(address market, Action action, bool paused) internal { + ensureListed(markets[market]); + _actionPaused[market][uint(action)] = paused; + emit ActionPausedMarket(VToken(market), action, paused); + } + + /** + * @notice Sets a new VAI controller + * @dev Admin function to set a new VAI controller + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setVAIController(VAIControllerInterface vaiController_) external returns (uint) { + // Check caller is admin + ensureAdmin(); + ensureNonzeroAddress(address(vaiController_)); + + VAIControllerInterface oldVaiController = vaiController; + vaiController = vaiController_; + emit NewVAIController(oldVaiController, vaiController_); + + return uint(Error.NO_ERROR); + } + + function _setVAIMintRate(uint newVAIMintRate) external returns (uint) { + // Check caller is admin + ensureAdmin(); + uint oldVAIMintRate = vaiMintRate; + vaiMintRate = newVAIMintRate; + emit NewVAIMintRate(oldVAIMintRate, newVAIMintRate); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Set the minted VAI amount of the `owner` + * @param owner The address of the account to set + * @param amount The amount of VAI to set to the account + * @return The number of minted VAI by `owner` + */ + function setMintedVAIOf(address owner, uint amount) external returns (uint) { + checkProtocolPauseState(); + + // Pausing is a very serious situation - we revert to sound the alarms + require(!mintVAIGuardianPaused && !repayVAIGuardianPaused, "VAI is paused"); + // Check caller is vaiController + if (msg.sender != address(vaiController)) { + return fail(Error.REJECTION, FailureInfo.SET_MINTED_VAI_REJECTION); + } + mintedVAIs[owner] = amount; + + return uint(Error.NO_ERROR); + } + + + function _setTreasuryData( + address newTreasuryGuardian, + address newTreasuryAddress, + uint newTreasuryPercent + ) external returns (uint) { + // Check caller is admin + ensureAdminOr(treasuryGuardian); + + require(newTreasuryPercent < 1e18, "treasury percent cap overflow"); + ensureNonzeroAddress(newTreasuryGuardian); + ensureNonzeroAddress(newTreasuryAddress); + + address oldTreasuryGuardian = treasuryGuardian; + address oldTreasuryAddress = treasuryAddress; + uint oldTreasuryPercent = treasuryPercent; + + treasuryGuardian = newTreasuryGuardian; + treasuryAddress = newTreasuryAddress; + treasuryPercent = newTreasuryPercent; + + emit NewTreasuryGuardian(oldTreasuryGuardian, newTreasuryGuardian); + emit NewTreasuryAddress(oldTreasuryAddress, newTreasuryAddress); + emit NewTreasuryPercent(oldTreasuryPercent, newTreasuryPercent); + + return uint(Error.NO_ERROR); + } + + function _become(Unitroller unitroller) external { + require(msg.sender == unitroller.admin(), "only unitroller admin can"); + require(unitroller._acceptImplementation() == 0, "not authorized"); + } + + /*** Venus Distribution ***/ + + /** + * @dev Set ComptrollerLens contract address + */ + function _setComptrollerLens(ComptrollerLensInterface comptrollerLens_) external returns (uint) { + ensureAdmin(); + ensureNonzeroAddress(address(comptrollerLens_)); + address oldComptrollerLens = address(comptrollerLens); + comptrollerLens = comptrollerLens_; + emit NewComptrollerLens(oldComptrollerLens, address(comptrollerLens)); + + return uint(Error.NO_ERROR); + } + + /** + * @notice Set the amount of XVS distributed per block to VAI Vault + * @param venusVAIVaultRate_ The amount of XVS wei per block to distribute to VAI Vault + */ + function _setVenusVAIVaultRate(uint venusVAIVaultRate_) external { + ensureAdmin(); + + uint oldVenusVAIVaultRate = venusVAIVaultRate; + venusVAIVaultRate = venusVAIVaultRate_; + emit NewVenusVAIVaultRate(oldVenusVAIVaultRate, venusVAIVaultRate_); + } + + /** + * @notice Set the VAI Vault infos + * @param vault_ The address of the VAI Vault + * @param releaseStartBlock_ The start block of release to VAI Vault + * @param minReleaseAmount_ The minimum release amount to VAI Vault + */ + function _setVAIVaultInfo(address vault_, uint256 releaseStartBlock_, uint256 minReleaseAmount_) external { + ensureAdmin(); + ensureNonzeroAddress(vault_); + + vaiVaultAddress = vault_; + releaseStartBlock = releaseStartBlock_; + minReleaseAmount = minReleaseAmount_; + emit NewVAIVaultInfo(vault_, releaseStartBlock_, minReleaseAmount_); + } + + /** + * @notice Sets the prime token contract for the comptroller + * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) + */ + function _setPrimeToken(IPrime _prime) external returns (uint) { + // Check caller is admin + ensureAdmin(); + ensureNonzeroAddress(address(_prime)); + + // Track the old prime token for the comptroller + IPrime oldPrime = prime; + + // Set comptroller's prime token to new prime token + prime = _prime; + + // Emit NewPrimeToken(oldPrime, newPrime) + emit NewPrimeToken(oldPrime, prime); + + return uint(Error.NO_ERROR); + } + + +} \ No newline at end of file