Skip to content

Commit

Permalink
add vault deployment script
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanzhelyazkov committed Oct 10, 2024
1 parent 3178fce commit 868b331
Show file tree
Hide file tree
Showing 7 changed files with 368 additions and 7 deletions.
4 changes: 3 additions & 1 deletion components/Contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import {
TestTokenType__factory,
TestUpgradeable__factory,
TestVoucher__factory,
Voucher__factory
Voucher__factory,
Vault__factory
} from '../typechain-types';
import { deployOrAttach } from './ContractBuilder';
import { Signer } from 'ethers';
Expand All @@ -37,6 +38,7 @@ const getContracts = (signer?: Signer) => ({
MockBancorNetworkV3: deployOrAttach('MockBancorNetworkV3', MockBancorNetworkV3__factory, signer),
ProxyAdmin: deployOrAttach('ProxyAdmin', ProxyAdmin__factory, signer),
Voucher: deployOrAttach('Voucher', Voucher__factory, signer),
Vault: deployOrAttach('Vault', Vault__factory, signer),
TestERC20FeeOnTransfer: deployOrAttach('TestERC20FeeOnTransfer', TestERC20FeeOnTransfer__factory, signer),
TestERC20Burnable: deployOrAttach('TestERC20Burnable', TestERC20Burnable__factory, signer),
TestERC20Token: deployOrAttach('TestERC20Token', TestERC20Token__factory, signer),
Expand Down
28 changes: 28 additions & 0 deletions contracts/helpers/TestReentrancyVault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import { Vault } from "../vault/Vault.sol";
import { Token } from "../token/Token.sol";

/**
* @dev test re-entrancy protection for Vault
*/
contract TestReentrancyVault {
Vault private immutable _vault;
Token private immutable _token;

constructor(Vault vaultInit, Token tokenInit) {
_vault = vaultInit;
_token = tokenInit;
}

receive() external payable {
// re-enter withdrawFunds, reverting the tx
_vault.withdrawFunds(_token, payable(address(this)), 1000);
}

/// @dev try to reenter withdraw funds
function tryReenterWithdrawFunds(Token token, address payable target, uint256 amount) external {
_vault.withdrawFunds(token, target, amount);
}
}
81 changes: 81 additions & 0 deletions contracts/vault/Vault.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import { AccessControlEnumerable } from "@openzeppelin/contracts/access/AccessControlEnumerable.sol";

import { Token } from "../token/Token.sol";

import { Utils, AccessDenied } from "../utility/Utils.sol";

contract Vault is ReentrancyGuard, AccessControlEnumerable, Utils {
using Address for address payable;
using SafeERC20 for IERC20;

// the admin role is used to grant and revoke the asset manager role
bytes32 internal constant ROLE_ADMIN = keccak256("ROLE_ADMIN");
// the asset manager role is required to access all the funds
bytes32 private constant ROLE_ASSET_MANAGER = keccak256("ROLE_ASSET_MANAGER");

/**
* @dev triggered when tokens have been withdrawn from the vault
*/
event FundsWithdrawn(Token indexed token, address indexed caller, address indexed target, uint256 amount);

/**
* @dev used to initialize the implementation
*/
constructor() {
// set up administrative roles
_setRoleAdmin(ROLE_ADMIN, ROLE_ADMIN);
_setRoleAdmin(ROLE_ASSET_MANAGER, ROLE_ADMIN);
// allow the deployer to initially be the admin of the contract
_setupRole(ROLE_ADMIN, msg.sender);
}

// solhint-enable func-name-mixedcase

/**
* @dev authorize the contract to receive the native token
*/
receive() external payable {}

/**
* @dev returns the admin role
*/
function roleAdmin() external pure returns (bytes32) {
return ROLE_ADMIN;
}

/**
* @dev returns the asset manager role
*/
function roleAssetManager() external pure returns (bytes32) {
return ROLE_ASSET_MANAGER;
}

/**
* @dev withdraws funds held by the contract and sends them to an account
*/
function withdrawFunds(
Token token,
address payable target,
uint256 amount
) external validAddress(target) nonReentrant {
if (!hasRole(ROLE_ASSET_MANAGER, msg.sender)) {
revert AccessDenied();
}

if (amount == 0) {
return;
}

// safe due to nonReentrant modifier (forwards all available gas in case of ETH)
token.unsafeTransfer(target, amount);

emit FundsWithdrawn({ token: token, caller: msg.sender, target: target, amount: amount });
}
}
31 changes: 31 additions & 0 deletions deploy/scripts/mainnet/0017-Vault.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { deploy, DeployedContracts, grantRole, InstanceName, setDeploymentMetadata } from '../../../utils/Deploy';
import { DeployFunction } from 'hardhat-deploy/types';
import { HardhatRuntimeEnvironment } from 'hardhat/types';
import { Roles } from '../../../utils/Roles';

/**
* @dev deploy vault and grant asset manager role to the vortex
*/
const func: DeployFunction = async ({ getNamedAccounts }: HardhatRuntimeEnvironment) => {
const { deployer } = await getNamedAccounts();

await deploy({
name: InstanceName.Vault,
from: deployer,
args: []
});

const carbonVortex = await DeployedContracts.CarbonVortex.deployed();

// grant asset manager role to carbon vortex
await grantRole({
name: InstanceName.Vault,
id: Roles.Vault.ROLE_ASSET_MANAGER,
member: carbonVortex.address,
from: deployer
});

return true;
};

export default setDeploymentMetadata(__filename, func);
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DeployFunction } from 'hardhat-deploy/types';
import { HardhatRuntimeEnvironment } from 'hardhat/types';
import { DeployedContracts, upgradeProxy, InstanceName, setDeploymentMetadata } from '../../../utils/Deploy';
import { DeployedContracts, upgradeProxy, InstanceName, setDeploymentMetadata, execute } from '../../../utils/Deploy';
import { NATIVE_TOKEN_ADDRESS } from '../../../utils/Constants';

/**
Expand All @@ -10,19 +10,29 @@ import { NATIVE_TOKEN_ADDRESS } from '../../../utils/Constants';
* make transfer address a settable variable
*/
const func: DeployFunction = async ({ getNamedAccounts }: HardhatRuntimeEnvironment) => {
const { deployer, bnt, vault } = await getNamedAccounts();
const { deployer, bnt } = await getNamedAccounts();
const carbonController = await DeployedContracts.CarbonController.deployed();

const vault = await DeployedContracts.Vault.deployed();

await upgradeProxy({
name: InstanceName.CarbonVortex,
from: deployer,
args: [carbonController.address, vault, NATIVE_TOKEN_ADDRESS, bnt],
args: [carbonController.address, vault.address, NATIVE_TOKEN_ADDRESS, bnt],
checkVersion: false,
proxy: {
args: [bnt]
}
});

// Set the transfer address to BNT in the vortex contract
await execute({
name: InstanceName.CarbonVortex,
methodName: 'setTransferAddress',
args: [bnt],
from: deployer
});

return true;
};

Expand Down
Loading

0 comments on commit 868b331

Please sign in to comment.