-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #106 from Ion-Protocol/jun/vault-rounding-error
Vault Deployment
- Loading branch information
Showing
16 changed files
with
1,751 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.21; | ||
|
||
import { Vault } from "./../../../src/vault/Vault.sol"; | ||
import { VaultFactory } from "./../../../src/vault/VaultFactory.sol"; | ||
import { IIonPool } from "./../../../src/interfaces/IIonPool.sol"; | ||
import { IonPool } from "./../../../src/IonPool.sol"; | ||
import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol"; | ||
|
||
import { BaseScript } from "./../../Base.s.sol"; | ||
|
||
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; | ||
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; | ||
import { stdJson as StdJson } from "forge-std/StdJson.sol"; | ||
|
||
VaultFactory constant factory = VaultFactory(address(0)); | ||
/** | ||
* Always use the factory to deploy a vault. | ||
*/ | ||
|
||
contract DeployVault is BaseScript { | ||
using EnumerableSet for EnumerableSet.AddressSet; | ||
using StdJson for string; | ||
using SafeCast for uint256; | ||
|
||
string configPath = "./deployment-config/vault/DeployVault.json"; | ||
string config = vm.readFile(configPath); | ||
|
||
VaultFactory factory = VaultFactory(config.readAddress(".factory")); | ||
|
||
address baseAsset = config.readAddress(".baseAsset"); | ||
|
||
address feeRecipient = config.readAddress(".feeRecipient"); | ||
uint256 feePercentage = config.readUint(".feePercentage"); | ||
|
||
string name = config.readString(".name"); | ||
string symbol = config.readString(".symbol"); | ||
|
||
uint48 initialDelay = config.readUint(".initialDelay").toUint48(); | ||
address initialDefaultAdmin = config.readAddress(".initialDefaultAdmin"); | ||
|
||
bytes32 salt = config.readBytes32(".salt"); | ||
|
||
uint256 initialDeposit = config.readUint(".initialDeposit"); | ||
|
||
address[] marketsToAdd = config.readAddressArray(".marketsToAdd"); | ||
uint256[] allocationCaps = config.readUintArray(".allocationCaps"); | ||
address[] supplyQueue = config.readAddressArray(".supplyQueue"); | ||
address[] withdrawQueue = config.readAddressArray(".withdrawQueue"); | ||
|
||
IIonPool public constant IDLE = IIonPool(address(uint160(uint256(keccak256("IDLE_ASSET_HOLDINGS"))))); | ||
|
||
EnumerableSet.AddressSet marketsCheck; | ||
|
||
/** | ||
* Validate that the salt is msg.sender protected. | ||
*/ | ||
function _validateSalt(bytes32 salt) internal { | ||
if (address(bytes20(salt)) != broadcaster) { | ||
revert("Invalid Salt"); | ||
} | ||
} | ||
|
||
/** | ||
* No duplicates. No zero addresses. IonPool Interface. | ||
*/ | ||
function _validateIonPoolArray(address[] memory ionPools) internal returns (IIonPool[] memory typedIonPools) { | ||
typedIonPools = new IIonPool[](ionPools.length); | ||
|
||
for (uint8 i = 0; i < ionPools.length; i++) { | ||
address pool = ionPools[i]; | ||
|
||
require(pool != address(0), "zero address"); | ||
|
||
marketsCheck.add(pool); | ||
|
||
// If not the IDLE address, then validate the IonPool interface. | ||
if (pool != address(IDLE)) { | ||
_validateInterfaceIonPool(IonPool(pool)); | ||
} | ||
|
||
// Check for duplicates in this array | ||
if (i != ionPools.length - 1) { | ||
for (uint8 j = i + 1; j < ionPools.length; j++) { | ||
require(ionPools[i] != ionPools[j], "duplicate"); | ||
} | ||
} | ||
|
||
typedIonPools[i] = IIonPool(pool); | ||
} | ||
} | ||
|
||
function run() public broadcast returns (Vault vault) { | ||
require(baseAsset != address(0), "baseAsset"); | ||
|
||
require(feeRecipient != address(0), "feeRecipient"); | ||
require(feePercentage <= 0.2e27, "feePercentage"); | ||
|
||
// require(initialDelay != 0, "initialDelay"); | ||
require(initialDefaultAdmin != address(0), "initialDefaultAdmin"); | ||
|
||
require(initialDeposit >= 1e3, "initialDeposit"); | ||
require(IERC20(baseAsset).balanceOf(broadcaster) >= initialDeposit, "sender balance"); | ||
// require(IERC20(baseAsset).allowance(broadcaster, address(factory)) >= initialDeposit, "sender allowance"); | ||
|
||
if (IERC20(baseAsset).allowance(broadcaster, address(factory)) < initialDeposit) { | ||
IERC20(baseAsset).approve(address(factory), 1e9); | ||
} | ||
|
||
// The length of all the arrays must be the same. | ||
require(marketsToAdd.length > 0); | ||
require(allocationCaps.length > 0); | ||
require(supplyQueue.length > 0); | ||
require(withdrawQueue.length > 0); | ||
|
||
uint256 marketsLength = marketsToAdd.length; | ||
|
||
require(marketsToAdd.length == marketsLength, "array length"); | ||
require(allocationCaps.length == marketsLength, "array length"); | ||
require(supplyQueue.length == marketsLength, "array length"); | ||
|
||
_validateSalt(salt); | ||
|
||
IIonPool[] memory typedMarketsToAdd = _validateIonPoolArray(marketsToAdd); | ||
IIonPool[] memory typedSupplyQueue = _validateIonPoolArray(supplyQueue); | ||
IIonPool[] memory typedWithdrawQueue = _validateIonPoolArray(withdrawQueue); | ||
|
||
// If the length of the `uniqueMarketsCheck` set is greater than 4, that | ||
// means not all of the IonPool arrays had the same set of markets. | ||
// `_validateIonPoolArray` must be called before this. | ||
require(marketsToAdd.length == marketsCheck.length(), "markets not consistent"); | ||
|
||
Vault.MarketsArgs memory marketsArgs = Vault.MarketsArgs({ | ||
marketsToAdd: typedMarketsToAdd, | ||
allocationCaps: allocationCaps, | ||
newSupplyQueue: typedSupplyQueue, | ||
newWithdrawQueue: typedWithdrawQueue | ||
}); | ||
|
||
vault = factory.createVault( | ||
IERC20(baseAsset), | ||
feeRecipient, | ||
feePercentage, | ||
name, | ||
symbol, | ||
initialDelay, | ||
initialDefaultAdmin, | ||
salt, | ||
marketsArgs, | ||
initialDeposit | ||
); | ||
|
||
require(vault.feeRecipient() == feeRecipient, "feeRecipient"); | ||
require(vault.feePercentage() == feePercentage, "feePercentage"); | ||
require(vault.defaultAdminDelay() == initialDelay, "initialDelay"); | ||
require(vault.defaultAdmin() == initialDefaultAdmin, "initialDefaultAdmin"); | ||
for (uint8 i = 0; i < marketsLength; i++) { | ||
require(vault.supplyQueue(i) == typedSupplyQueue[i], "supplyQueue"); | ||
require(vault.withdrawQueue(i) == typedWithdrawQueue[i], "withdrawQueue"); | ||
} | ||
require(vault.supportedMarketsLength() == marketsLength, "supportedMarkets"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.21; | ||
|
||
import { VaultBytecode } from "./../../../src/vault/VaultBytecode.sol"; | ||
import { CREATEX } from "./../../../src/Constants.sol"; | ||
|
||
import { DeployScript } from "./../../Deploy.s.sol"; | ||
|
||
bytes32 constant SALT = 0xbcde1e1dd0bdb803514d8e000000000000000000000000000000000000000000; | ||
|
||
contract DeployVaultBytecode is DeployScript { | ||
function run() public broadcast returns (VaultBytecode vaultBytecode) { | ||
bytes memory initCode = type(VaultBytecode).creationCode; | ||
|
||
require(initCode.length > 0, "initCode"); | ||
require(SALT != bytes32(0), "salt"); | ||
|
||
vaultBytecode = VaultBytecode(CREATEX.deployCreate3(SALT, initCode)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.21; | ||
|
||
import { VaultFactory } from "./../../../src/vault/VaultFactory.sol"; | ||
import { CREATEX } from "./../../../src/Constants.sol"; | ||
|
||
import { DeployScript } from "./../../Deploy.s.sol"; | ||
|
||
// deploys to 0x0000000000d7dc416dfe993b0e3dd53ba3e27fc8 | ||
bytes32 constant SALT = 0x2f428c0d9f1d9e00034c85000000000000000000000000000000000000000000; | ||
|
||
contract DeployVaultFactory is DeployScript { | ||
function run() public broadcast returns (VaultFactory vaultFactory) { | ||
bytes memory initCode = type(VaultFactory).creationCode; | ||
|
||
require(initCode.length > 0, "initCode"); | ||
require(SALT != bytes32(0), "salt"); | ||
|
||
vaultFactory = VaultFactory(CREATEX.deployCreate3(SALT, initCode)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
pragma solidity 0.8.21; | ||
|
||
import { Vault } from "./Vault.sol"; | ||
import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol"; | ||
|
||
/** | ||
* @title VaultBytecode | ||
* @author Molecular Labs | ||
* @notice The sole job of this contract is to deploy the embedded `Vault` | ||
* contract's bytecode with the constructor args. `VaultFactory` handles rest of | ||
* the verification and post-deployment logic. | ||
*/ | ||
contract VaultBytecode { | ||
error OnlyFactory(); | ||
|
||
address constant VAULT_FACTORY = 0x0000000000D7DC416dFe993b0E3dd53BA3E27Fc8; | ||
|
||
/** | ||
* @notice Deploys the embedded `Vault` bytecode with the given constructor | ||
* args. Only the `VaultFactory` contract can call this function. | ||
* @dev This contract was separated from `VaultFactory` to reduce the | ||
* codesize of the factory contract. | ||
* @param baseAsset The asset that is being lent out to IonPools. | ||
* @param feeRecipient Address that receives the accrued manager fees. | ||
* @param feePercentage Fee percentage to be set. | ||
* @param name Name of the vault token. | ||
* @param symbol Symbol of the vault token. | ||
* @param initialDelay The initial delay for default admin transfers. | ||
* @param initialDefaultAdmin The initial default admin for the vault. | ||
* @param salt The salt used for CREATE2 deployment. The first 20 bytes must | ||
* be the msg.sender. | ||
* @param marketsArgs Arguments for the markets to be added to the vault. | ||
*/ | ||
function deploy( | ||
IERC20 baseAsset, | ||
address feeRecipient, | ||
uint256 feePercentage, | ||
string memory name, | ||
string memory symbol, | ||
uint48 initialDelay, | ||
address initialDefaultAdmin, | ||
bytes32 salt, | ||
Vault.MarketsArgs memory marketsArgs | ||
) | ||
external | ||
returns (Vault vault) | ||
{ | ||
if (msg.sender != VAULT_FACTORY) revert OnlyFactory(); | ||
|
||
vault = new Vault{ salt: salt }( | ||
baseAsset, feeRecipient, feePercentage, name, symbol, initialDelay, initialDefaultAdmin, marketsArgs | ||
); | ||
} | ||
} |
Oops, something went wrong.