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

[VEN-2109]: add ethereum xvs vault deployments #390

Closed
wants to merge 8 commits into from
Closed
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
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ coverage.json
npm-debug.log*
yarn-debug.log*
yarn-error.log*
CHANGELOG.md
CHANGELOG.md
docgen-docs
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
## [6.0.0-dev.3](https://github.com/VenusProtocol/venus-protocol/compare/v6.0.0-dev.2...v6.0.0-dev.3) (2023-11-21)

## [6.0.0-dev.2](https://github.com/VenusProtocol/venus-protocol/compare/v6.0.0-dev.1...v6.0.0-dev.2) (2023-11-16)


Expand Down
14 changes: 7 additions & 7 deletions contracts/Vault/VAIVault.sol → contracts/VAIVault/VAIVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import "../Utils/IBEP20.sol";
import "./VAIVaultStorage.sol";
import "./VAIVaultErrorReporter.sol";
import "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV5.sol";
import { VAIVaultProxy } from "./VAIVaultProxy.sol";

interface IVAIVaultProxy {
function _acceptImplementation() external returns (uint);

function admin() external returns (address);
}

/**
* @title VAI Vault
* @author Venus
* @notice The VAI Vault is configured for users to stake VAI And receive XVS as a reward.
*/
contract VAIVault is VAIVaultStorage, AccessControlledV5 {
using SafeMath for uint256;
using SafeBEP20 for IBEP20;
Expand Down Expand Up @@ -213,7 +213,7 @@ contract VAIVault is VAIVaultStorage, AccessControlledV5 {

/*** Admin Functions ***/

function _become(IVAIVaultProxy vaiVaultProxy) external {
function _become(VAIVaultProxy vaiVaultProxy) external {
require(msg.sender == vaiVaultProxy.admin(), "only proxy admin can change brains");
require(vaiVaultProxy._acceptImplementation() == 0, "change not authorized");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ pragma solidity ^0.5.16;
import "./VAIVaultStorage.sol";
import "./VAIVaultErrorReporter.sol";

/**
* @title VAI Vault Proxy
* @author Venus
* @notice Proxy contract for the VAI Vault
*/
contract VAIVaultProxy is VAIVaultAdminStorage, VAIVaultErrorReporter {
/**
* @notice Emitted when pendingVAIVaultImplementation is changed
Expand Down
38 changes: 37 additions & 1 deletion contracts/XVSVault/XVSStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ pragma solidity 0.5.16;
import "../Utils/SafeBEP20.sol";
import "../Utils/IBEP20.sol";

/**
* @title XVS Store
* @author Venus
* @notice XVS Store responsible for distributing XVS rewards
*/
contract XVSStore {
using SafeMath for uint256;
using SafeBEP20 for IBEP20;
Expand Down Expand Up @@ -41,7 +46,14 @@ contract XVSStore {
_;
}

// Safe reward token transfer function, just in case if rounding error causes pool to not have enough tokens.
/**
* @notice Safely transfer rewards. Only active reward tokens can be sent using this function.
* Only callable by owner
* @dev Safe reward token transfer function, just in case if rounding error causes pool to not have enough tokens.
* @param token Reward token to transfer
* @param _to Destination address of the reward
* @param _amount Amount to transfer
*/
function safeRewardTransfer(address token, address _to, uint256 _amount) external onlyOwner {
require(rewardTokens[token] == true, "only reward token can");

Expand All @@ -55,12 +67,21 @@ contract XVSStore {
}
}

/**
* @notice Allows the admin to propose a new admin
* Only callable admin
* @param _admin Propose an account as admin of the XVS store
*/
function setPendingAdmin(address _admin) external onlyAdmin {
address oldPendingAdmin = pendingAdmin;
pendingAdmin = _admin;
emit NewPendingAdmin(oldPendingAdmin, _admin);
}

/**
* @notice Allows an account that is pending as admin to accept the role
* nly calllable by the pending admin
*/
function acceptAdmin() external {
require(msg.sender == pendingAdmin, "only pending admin");
address oldAdmin = admin;
Expand All @@ -73,18 +94,33 @@ contract XVSStore {
emit AdminTransferred(oldAdmin, admin);
}

/**
* @notice Set the contract owner
* @param _owner The address of the owner to set
* Only callable admin
*/
function setNewOwner(address _owner) external onlyAdmin {
require(_owner != address(0), "new owner is the zero address");
address oldOwner = owner;
owner = _owner;
emit OwnerTransferred(oldOwner, _owner);
}

/**
* @notice Set or disable a reward token
* @param _tokenAddress The address of a token to set as active or inactive
* @param status Set whether a reward token is active or not
*/
function setRewardToken(address _tokenAddress, bool status) external {
require(msg.sender == admin || msg.sender == owner, "only admin or owner can");
rewardTokens[_tokenAddress] = status;
}

/**
* @notice Security function to allow the owner of the contract to withdraw from the contract
* @param _tokenAddress Reward token address to withdraw
* @param _amount Amount of token to withdraw
*/
function emergencyRewardWithdraw(address _tokenAddress, uint256 _amount) external onlyOwner {
IBEP20(_tokenAddress).safeTransfer(address(msg.sender), _amount);
}
Expand Down
35 changes: 14 additions & 21 deletions contracts/XVSVault/XVSVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,14 @@ import "./XVSVaultErrorReporter.sol";
import "../Tokens/Prime/IPrime.sol";
import "../Utils/SafeCast.sol";
import "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV5.sol";

interface IXVSStore {
function safeRewardTransfer(address _token, address _to, uint256 _amount) external;

function setRewardToken(address _tokenAddress, bool status) external;

function rewardTokens(address _tokenAddress) external view returns (bool);
}

interface IXVSVaultProxy {
function _acceptImplementation() external returns (uint);

function admin() external returns (address);
}

import { XVSStore } from "./XVSStore.sol";
import { XVSVaultProxy } from "./XVSVaultProxy.sol";

/**
* @title XVS Vault
* @author Venus
* @notice The XVS Vault allows XVS holders to lock their XVS to recieve voting rights in Venus governance and are rewarded with XVS.
*/
contract XVSVault is XVSVaultStorage, ECDSA, AccessControlledV5 {
using SafeMath for uint256;
using SafeCast for uint256;
Expand Down Expand Up @@ -207,7 +200,7 @@ contract XVSVault is XVSVaultStorage, ECDSA, AccessControlledV5 {
);
isStakedToken[address(_token)] = true;

IXVSStore(xvsStore).setRewardToken(_rewardToken, true);
XVSStore(xvsStore).setRewardToken(_rewardToken, true);

emit PoolAdded(_rewardToken, poolInfo.length - 1, address(_token), _allocPoint, _rewardPerBlock, _lockPeriod);
}
Expand Down Expand Up @@ -242,7 +235,7 @@ contract XVSVault is XVSVaultStorage, ECDSA, AccessControlledV5 {
*/
function setRewardAmountPerBlock(address _rewardToken, uint256 _rewardAmount) external {
_checkAccessAllowed("setRewardAmountPerBlock(address,uint256)");
require(IXVSStore(xvsStore).rewardTokens(_rewardToken), "Invalid reward token");
require(XVSStore(xvsStore).rewardTokens(_rewardToken), "Invalid reward token");
massUpdatePools(_rewardToken);
uint256 oldReward = rewardTokenAmountsPerBlock[_rewardToken];
rewardTokenAmountsPerBlock[_rewardToken] = _rewardAmount;
Expand Down Expand Up @@ -421,7 +414,7 @@ contract XVSVault is XVSVaultStorage, ECDSA, AccessControlledV5 {
if (beforeUpgradeWithdrawalAmount > 0) {
_updatePool(_rewardToken, _pid);
uint256 pending = user.amount.mul(pool.accRewardPerShare).div(1e12).sub(user.rewardDebt);
IXVSStore(xvsStore).safeRewardTransfer(_rewardToken, msg.sender, pending);
XVSStore(xvsStore).safeRewardTransfer(_rewardToken, msg.sender, pending);
user.amount = user.amount.sub(beforeUpgradeWithdrawalAmount);
user.rewardDebt = user.amount.mul(pool.accRewardPerShare).div(1e12);
pool.token.safeTransfer(address(msg.sender), beforeUpgradeWithdrawalAmount);
Expand Down Expand Up @@ -845,7 +838,7 @@ contract XVSVault is XVSVaultStorage, ECDSA, AccessControlledV5 {

/*** Admin Functions ***/

function _become(IXVSVaultProxy xvsVaultProxy) external {
function _become(XVSVaultProxy xvsVaultProxy) external {
require(msg.sender == xvsVaultProxy.admin(), "only proxy admin can change brains");
require(xvsVaultProxy._acceptImplementation() == 0, "change not authorized");
}
Expand Down Expand Up @@ -921,14 +914,14 @@ contract XVSVault is XVSVaultStorage, ECDSA, AccessControlledV5 {
pendingRewardTransfers[rewardToken][userAddress] = 0;
emit VaultDebtUpdated(rewardToken, userAddress, debtDueToFailedTransfers, 0);
}
IXVSStore(xvsStore_).safeRewardTransfer(rewardToken, userAddress, fullAmount);
XVSStore(xvsStore_).safeRewardTransfer(rewardToken, userAddress, fullAmount);
return;
}
// Overflow isn't possible due to the check above
uint256 newOwedAmount = fullAmount - storeBalance;
pendingRewardTransfers[rewardToken][userAddress] = newOwedAmount;
emit VaultDebtUpdated(rewardToken, userAddress, debtDueToFailedTransfers, newOwedAmount);
IXVSStore(xvsStore_).safeRewardTransfer(rewardToken, userAddress, storeBalance);
XVSStore(xvsStore_).safeRewardTransfer(rewardToken, userAddress, storeBalance);
}

/**
Expand Down
5 changes: 5 additions & 0 deletions contracts/XVSVault/XVSVaultProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ pragma solidity ^0.5.16;
import "./XVSVaultStorage.sol";
import "./XVSVaultErrorReporter.sol";

/**
* @title XVS Vault Proxy
* @author Venus
* @notice XVS Vault Proxy contract
*/
contract XVSVaultProxy is XVSVaultAdminStorage, XVSVaultErrorReporter {
/**
* @notice Emitted when pendingXVSVaultImplementation is changed
Expand Down
28 changes: 28 additions & 0 deletions deploy/007-deploy-xvs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { DeployFunction } from "hardhat-deploy/types";
import { HardhatRuntimeEnvironment } from "hardhat/types";

const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployments, getNamedAccounts } = hre;
const { deploy } = deployments;
const { deployer } = await getNamedAccounts();

await deploy("XVS", {
from: deployer,
args: [deployer],
log: true,
autoMine: true,
});

await deploy("AccessControlManager", {
from: deployer,
args: [],
log: true,
autoMine: true,
});
};

func.tags = ["xvs"];

func.skip = async (hre: HardhatRuntimeEnvironment) => hre.network.live;

export default func;
53 changes: 53 additions & 0 deletions deploy/008-deploy-vaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ethers } from "hardhat";
import { DeployFunction } from "hardhat-deploy/types";
import { HardhatRuntimeEnvironment } from "hardhat/types";

const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployments, getNamedAccounts } = hre;
const { deploy } = deployments;
const { deployer } = await getNamedAccounts();

const xvsVaultDeployment = await deploy("XVSVault", {
from: deployer,
args: [],
log: true,
autoMine: true,
});

const xvsVaultAddress = xvsVaultDeployment.address;

const xvsVaultProxyDeployment = await deploy("XVSVaultProxy", {
from: deployer,
args: [],
log: true,
autoMine: true,
});

const xvsVaultProxyAddress = xvsVaultProxyDeployment.address;

await deploy("XVSStore", {
from: deployer,
args: [],
log: true,
autoMine: true,
});

const xvsVault = await ethers.getContract("XVSVault");
const xvsStore = await ethers.getContract("XVSStore");
const xvsVaultProxy = await ethers.getContract("XVSVaultProxy");

// Become Implementation of XVSVaultProxy
const tx = await xvsVaultProxy._setPendingImplementation(xvsVaultAddress);
await tx.wait();

await xvsVault._become(xvsVaultProxyAddress);
await tx.wait();

// Set new owner to xvs store
await xvsStore.setNewOwner(xvsVaultAddress);
await tx.wait();
};

func.tags = ["xvs-vault"];

export default func;
67 changes: 67 additions & 0 deletions deploy/009-configure-vaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import deployedContracts from "@venusprotocol/governance-contracts/deployments/deployments.json";
import { ethers } from "hardhat";
import { DeployFunction } from "hardhat-deploy/types";
import { HardhatRuntimeEnvironment } from "hardhat/types";

interface AdminAccounts {
[key: string]: string;
}
const adminAccount: AdminAccounts = {
sepolia: "0x94fa6078b6b8a26f0b6edffbe6501b22a10470fb", // SEPOLIA MULTISIG
ethereum: "0x285960C5B22fD66A736C7136967A3eB15e93CC67", // ETHEREUM MULTISIG
};

const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { getNamedAccounts } = hre;
const { deployer } = await getNamedAccounts();

const chainId = (await hre.getChainId()) as keyof typeof deployedContracts;
const accessControlManager = hre.network.live
? await ethers.getContractAt(
"AccessControlManager",
deployedContracts[chainId][0].contracts.AccessControlManager.address,
)
: await ethers.getContract("AccessControlManager");

const xvs = await ethers.getContract("XVS");
const xvsVaultProxyDeployment = await ethers.getContract("XVSVaultProxy");
const xvsStoreDeployment = await ethers.getContract("XVSStore");

const xvsVaultProxy = await ethers.getContractAt("XVSVault", xvsVaultProxyDeployment.address);

let txn = await xvsVaultProxy.setXvsStore(xvs.address, xvsStoreDeployment.address);
await txn.wait();

txn = await xvsVaultProxy.setAccessControl(accessControlManager.address);
await txn.wait();

if (!hre.network.live) {
const tx = await accessControlManager.giveCallPermission(
ethers.constants.AddressZero,
"add(address,uint256,address,uint256,uint256)",
deployer,
);
await tx.wait();

// Add token pool to xvs vault
const allocPoint = 100;
const token = xvs.address;
const rewardToken = xvs.address;
const rewardPerBlock = "61805555555555555";
const lockPeriod = 604800;

await xvsVaultProxy.add(rewardToken, allocPoint, token, rewardPerBlock, lockPeriod);
} else {
const owner = adminAccount[hre.network.name];
console.log("Please accept ownership of vault and store");
txn = await xvsVaultProxyDeployment._setPendingAdmin(owner);
await txn.wait();

txn = await xvsStoreDeployment.setPendingAdmin(owner);
await txn.wait();
}
};

func.tags = ["xvs-vault"];

export default func;
Loading
Loading