From c1205aa2472df2e37dd019a30a37363b2e462ba7 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Thu, 6 Apr 2023 13:01:03 +0200 Subject: [PATCH 01/31] fix issue https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/468 --- src/v2/Carousel/Carousel.sol | 3 +- src/v2/CustomERC1155/ERC1155.sol | 519 +++++++++++++++++++++++++ src/v2/CustomERC1155/ERC1155Supply.sol | 64 +++ src/v2/SemiFungibleVault.sol | 4 +- test/V2/Carousel/CarouselTest.t.sol | 10 +- 5 files changed, 596 insertions(+), 4 deletions(-) create mode 100644 src/v2/CustomERC1155/ERC1155.sol create mode 100644 src/v2/CustomERC1155/ERC1155Supply.sol diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index ed460af3..74e7a81c 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -71,7 +71,8 @@ contract Carousel is VaultV2 { //////////////////////////////////////////////////////////////*/ /** @notice Deposit function - @param _id epoch id + @dev if receiver intends to deposit into queue and is contract, it must implement 1155 receiver interface otherwise funds will be stuck + @param _id epoch id, if 0 deposit will be queued; @param _assets uint256 of how many assets you want to deposit; @param _receiver address of the receiver of the shares provided by this function, that represent the ownership of the deposited asset; */ diff --git a/src/v2/CustomERC1155/ERC1155.sol b/src/v2/CustomERC1155/ERC1155.sol new file mode 100644 index 00000000..b07dee0e --- /dev/null +++ b/src/v2/CustomERC1155/ERC1155.sol @@ -0,0 +1,519 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/ERC1155.sol) + +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; +import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; +import "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; +import "@openzeppelin/contracts/utils/Context.sol"; +import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of the basic standard multi-token. + * See https://eips.ethereum.org/EIPS/eip-1155 + * Originally based on code by Enjin: https://github.com/enjin/erc-1155 + * + * _Available since v3.1._ + */ +contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { + using Address for address; + + // Mapping from token ID to account balances + mapping(uint256 => mapping(address => uint256)) private _balances; + + // Mapping from account to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json + string private _uri; + + /** + * @dev See {_setURI}. + */ + constructor(string memory uri_) { + _setURI(uri_); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC1155).interfaceId || + interfaceId == type(IERC1155MetadataURI).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the same URI for *all* token types. It relies + * on the token type ID substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * Clients calling this function must replace the `\{id\}` substring with the + * actual token type ID. + */ + function uri(uint256) public view virtual override returns (string memory) { + return _uri; + } + + /** + * @dev See {IERC1155-balanceOf}. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { + require(account != address(0), "ERC1155: address zero is not a valid owner"); + return _balances[id][account]; + } + + /** + * @dev See {IERC1155-balanceOfBatch}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch(address[] memory accounts, uint256[] memory ids) + public + view + virtual + override + returns (uint256[] memory) + { + require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); + + uint256[] memory batchBalances = new uint256[](accounts.length); + + for (uint256 i = 0; i < accounts.length; ++i) { + batchBalances[i] = balanceOf(accounts[i], ids[i]); + } + + return batchBalances; + } + + /** + * @dev See {IERC1155-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC1155-isApprovedForAll}. + */ + function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { + return _operatorApprovals[account][operator]; + } + + /** + * @dev See {IERC1155-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) public virtual override { + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()), + "ERC1155: caller is not owner nor approved" + ); + _safeTransferFrom(from, to, id, amount, data); + } + + /** + * @dev See {IERC1155-safeBatchTransferFrom}. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) public virtual override { + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()), + "ERC1155: transfer caller is not owner nor approved" + ); + _safeBatchTransferFrom(from, to, ids, amounts, data); + } + + /** + * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `from` must have a balance of tokens of type `id` of at least `amount`. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155: transfer to the zero address"); + + address operator = _msgSender(); + uint256[] memory ids = _asSingletonArray(id); + uint256[] memory amounts = _asSingletonArray(amount); + + _beforeTokenTransfer(operator, from, to, ids, amounts, data); + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + _balances[id][to] += amount; + + emit TransferSingle(operator, from, to, id, amount); + + _afterTokenTransfer(operator, from, to, ids, amounts, data); + + _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + require(to != address(0), "ERC1155: transfer to the zero address"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, to, ids, amounts, data); + + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + _balances[id][to] += amount; + } + + emit TransferBatch(operator, from, to, ids, amounts); + + _afterTokenTransfer(operator, from, to, ids, amounts, data); + + _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); + } + + /** + * @dev Sets a new URI for all token types, by relying on the token type ID + * substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * By this mechanism, any occurrence of the `\{id\}` substring in either the + * URI or any of the amounts in the JSON file at said URI will be replaced by + * clients with the token type ID. + * + * For example, the `https://token-cdn-domain/\{id\}.json` URI would be + * interpreted by clients as + * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` + * for token type ID 0x4cce0. + * + * See {uri}. + * + * Because these URIs cannot be meaningfully represented by the {URI} event, + * this function emits no events. + */ + function _setURI(string memory newuri) internal virtual { + _uri = newuri; + } + + /** + * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _mint( + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155: mint to the zero address"); + + address operator = _msgSender(); + uint256[] memory ids = _asSingletonArray(id); + uint256[] memory amounts = _asSingletonArray(amount); + + _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); + + _balances[id][to] += amount; + emit TransferSingle(operator, address(0), to, id, amount); + + _afterTokenTransfer(operator, address(0), to, ids, amounts, data); + + // remove _doSafeTransferAcceptanceCheck to prevent reverting in queue + // if receiver is a contract and does not implement the ERC1155Holder interface funds will be stuck + // _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _mintBatch( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155: mint to the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); + + for (uint256 i = 0; i < ids.length; i++) { + _balances[ids[i]][to] += amounts[i]; + } + + emit TransferBatch(operator, address(0), to, ids, amounts); + + _afterTokenTransfer(operator, address(0), to, ids, amounts, data); + + _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); + } + + /** + * @dev Destroys `amount` tokens of token type `id` from `from` + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `from` must have at least `amount` tokens of token type `id`. + */ + function _burn( + address from, + uint256 id, + uint256 amount + ) internal virtual { + require(from != address(0), "ERC1155: burn from the zero address"); + + address operator = _msgSender(); + uint256[] memory ids = _asSingletonArray(id); + uint256[] memory amounts = _asSingletonArray(amount); + + _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + + emit TransferSingle(operator, from, address(0), id, amount); + + _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + */ + function _burnBatch( + address from, + uint256[] memory ids, + uint256[] memory amounts + ) internal virtual { + require(from != address(0), "ERC1155: burn from the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); + + for (uint256 i = 0; i < ids.length; i++) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + } + + emit TransferBatch(operator, from, address(0), ids, amounts); + + _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Emits an {ApprovalForAll} event. + */ + function _setApprovalForAll( + address owner, + address operator, + bool approved + ) internal virtual { + require(owner != operator, "ERC1155: setting approval status for self"); + _operatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `ids` and `amounts` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual {} + + /** + * @dev Hook that is called after any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `id` and `amount` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual {} + + function _doSafeTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) private { + if (to.isContract()) { + try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { + if (response != IERC1155Receiver.onERC1155Received.selector) { + revert("ERC1155: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155: transfer to non ERC1155Receiver implementer"); + } + } + } + + function _doSafeBatchTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) private { + if (to.isContract()) { + try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns ( + bytes4 response + ) { + if (response != IERC1155Receiver.onERC1155BatchReceived.selector) { + revert("ERC1155: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155: transfer to non ERC1155Receiver implementer"); + } + } + } + + function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { + uint256[] memory array = new uint256[](1); + array[0] = element; + + return array; + } +} diff --git a/src/v2/CustomERC1155/ERC1155Supply.sol b/src/v2/CustomERC1155/ERC1155Supply.sol new file mode 100644 index 00000000..2303c3c6 --- /dev/null +++ b/src/v2/CustomERC1155/ERC1155Supply.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/extensions/ERC1155Supply.sol) + +pragma solidity ^0.8.0; + +import "./ERC1155.sol"; + +/** + * @dev Extension of ERC1155 that adds tracking of total supply per id. + * + * Useful for scenarios where Fungible and Non-fungible tokens have to be + * clearly identified. Note: While a totalSupply of 1 might mean the + * corresponding is an NFT, there is no guarantees that no other token with the + * same id are not going to be minted. + */ +abstract contract ERC1155Supply is ERC1155 { + mapping(uint256 => uint256) private _totalSupply; + + /** + * @dev Total amount of tokens in with a given id. + */ + function totalSupply(uint256 id) public view virtual returns (uint256) { + return _totalSupply[id]; + } + + /** + * @dev Indicates whether any token exist with a given id, or not. + */ + function exists(uint256 id) public view virtual returns (bool) { + return ERC1155Supply.totalSupply(id) > 0; + } + + /** + * @dev See {ERC1155-_beforeTokenTransfer}. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual override { + super._beforeTokenTransfer(operator, from, to, ids, amounts, data); + + if (from == address(0)) { + for (uint256 i = 0; i < ids.length; ++i) { + _totalSupply[ids[i]] += amounts[i]; + } + } + + if (to == address(0)) { + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + uint256 supply = _totalSupply[id]; + require(supply >= amount, "ERC1155: burn amount exceeds totalSupply"); + unchecked { + _totalSupply[id] = supply - amount; + } + } + } + } +} diff --git a/src/v2/SemiFungibleVault.sol b/src/v2/SemiFungibleVault.sol index 3e7c2f15..e21c615f 100644 --- a/src/v2/SemiFungibleVault.sol +++ b/src/v2/SemiFungibleVault.sol @@ -7,8 +7,8 @@ import { } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ERC1155Supply -} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol"; -import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +} from "./CustomERC1155/ERC1155Supply.sol"; +import {ERC1155} from "./CustomERC1155/ERC1155.sol"; import {ISemiFungibleVault} from "./interfaces/ISemiFungibleVault.sol"; /// @author MiguelBits diff --git a/test/V2/Carousel/CarouselTest.t.sol b/test/V2/Carousel/CarouselTest.t.sol index 7caa6858..6bdc1695 100644 --- a/test/V2/Carousel/CarouselTest.t.sol +++ b/test/V2/Carousel/CarouselTest.t.sol @@ -126,7 +126,15 @@ contract CarouselTest is Helper { vault.deposit(0, 10 ether, USER2); vm.stopPrank(); - _queueLength = 2; + // test deposit into queue with non 1155 complient receiver + // queue should not revert + vm.startPrank(USER2); + address faultyReceiver = address(new MintableToken("faulty contract", "faulty")); + IERC20(UNDERLYING).approve(address(vault), 10 ether); + vault.deposit(0, 10 ether, faultyReceiver); + vm.stopPrank(); + + _queueLength = 3; assertEq(vault.getDepositQueueLenght(), _queueLength); // should only do as many operations as queue length From 413b28ac36efbbd439fab670686d349664b977f0 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Thu, 6 Apr 2023 14:58:54 +0200 Subject: [PATCH 02/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/163 --- src/v2/Carousel/Carousel.sol | 19 ++++++++++++------- test/V2/Carousel/CarouselTest.t.sol | 7 +++++++ test/V2/Helper.sol | 4 ++-- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index 74e7a81c..b96f0637 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -394,35 +394,40 @@ contract Carousel is VaultV2 { while ((index - prevIndex) < (_operations)) { // only roll over if last epoch is resolved if (epochResolved[queue[index].epochId]) { - uint256 entitledShares = previewWithdraw( + uint256 entitledAmount = previewWithdraw( queue[index].epochId, queue[index].assets ); // mint only if user won epoch he is rolling over - if (entitledShares > queue[index].assets) { + if (entitledAmount > queue[index].assets) { + uint256 diff = entitledAmount - queue[index].assets; + // get diff amount in assets + uint256 diffInAssets = diff.mulDivUp(finalTVL[queue[index].epochId], claimTVL[queue[index].epochId]); // skip the rollover for the user if the assets cannot cover the relayer fee instead of revert. if (queue[index].assets < relayerFee) { index++; continue; } + + uint256 originalDepositValue = queue[index].assets - diffInAssets; // @note we know shares were locked up to this point _burn( queue[index].receiver, queue[index].epochId, - queue[index].assets + originalDepositValue ); // transfer emission tokens out of contract otherwise user could not access them as vault shares are burned _burnEmissions( queue[index].receiver, queue[index].epochId, - queue[index].assets + originalDepositValue ); // @note emission token is a known token which has no before transfer hooks which makes transfer safer emissionsToken.safeTransfer( queue[index].receiver, previewEmissionsWithdraw( queue[index].epochId, - queue[index].assets + originalDepositValue ) ); @@ -431,8 +436,8 @@ contract Carousel is VaultV2 { queue[index].receiver, queue[index].receiver, _epochId, - queue[index].assets, - entitledShares + originalDepositValue, + entitledAmount ); uint256 assetsToMint = queue[index].assets - relayerFee; _mintShares(queue[index].receiver, _epochId, assetsToMint); diff --git a/test/V2/Carousel/CarouselTest.t.sol b/test/V2/Carousel/CarouselTest.t.sol index 6bdc1695..6915347a 100644 --- a/test/V2/Carousel/CarouselTest.t.sol +++ b/test/V2/Carousel/CarouselTest.t.sol @@ -320,6 +320,9 @@ contract CarouselTest is Helper { console.log("rollover queue length", vault.getRolloverQueueLenght()); + // get value of prev epoch sahres for user + uint256 prevEpochShareValue = vault.previewWithdraw(prevEpoch, vault.balanceOf(USER, prevEpoch)); + // mint rollovers again // this should mint shares as prev epoch is in profit // should only mint as many positions as there are in queue (6) @@ -333,6 +336,10 @@ contract CarouselTest is Helper { uint256 _relayerFee = (balanceAfter - balanceBefore) / 6; assertEq(_relayerFee, relayerFee); + //@note after rollover, prev value of shares should subtract by original deposit value + uint256 prevEpochSharesValueAfterRollover = vault.previewWithdraw(prevEpoch, vault.balanceOf(USER, prevEpoch)); + assertEq(((prevEpochSharesValueAfterRollover >> 1) << 1) , ((prevEpochShareValue - prevEpochUserBalance) >> 1) << 1); // zero out last bit to avoid rounding errors + // check balances assertEq(vault.balanceOf(USER, _epochId), prevEpochUserBalance - relayerFee); assertEq(vault.balanceOfEmissions(USER, _epochId), prevEpochUserBalance - relayerFee); diff --git a/test/V2/Helper.sol b/test/V2/Helper.sol index feb1f88f..db1d8153 100644 --- a/test/V2/Helper.sol +++ b/test/V2/Helper.sol @@ -10,8 +10,8 @@ contract Helper is Test { uint256 public constant COLLATERAL_MINUS_FEES = 21989999998407999999; uint256 public constant COLLATERAL_MINUS_FEES_DIV10 = 2198999999840799999; uint256 public constant NEXT_COLLATERAL_MINUS_FEES = 21827317001456829250; - uint256 public constant USER1_EMISSIONS_AFTER_WITHDRAW = 1099999999999999999749; - uint256 public constant USER2_EMISSIONS_AFTER_WITHDRAW = 99999999999999999749; + uint256 public constant USER1_EMISSIONS_AFTER_WITHDRAW = 1096380172807730660741; + uint256 public constant USER2_EMISSIONS_AFTER_WITHDRAW = 96380172807730660741; uint256 public constant USER_AMOUNT_AFTER_WITHDRAW = 13112658495641799945; address public constant ADMIN = address(0x1); address public constant WETH = address(0x888); From f6e9e28182b69168a6ac57cdc16acee284210f21 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Thu, 6 Apr 2023 16:09:49 +0200 Subject: [PATCH 03/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/75 --- src/v2/Carousel/Carousel.sol | 58 ++++++++++++++++------ src/v2/Carousel/CarouselFactory.sol | 7 ++- src/v2/libraries/CarouselCreator.sol | 4 +- test/V2/Carousel/CarouselFactoryTest.t.sol | 6 ++- test/V2/Carousel/CarouselTest.t.sol | 3 +- test/V2/Helper.sol | 10 ++-- test/V2/e2e/EndToEndCarouselTest.t.sol | 18 ++++--- 7 files changed, 73 insertions(+), 33 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index b96f0637..09ce2866 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -20,6 +20,7 @@ contract Carousel is VaultV2 { // Earthquake parameters uint256 public relayerFee; uint256 public depositFee; + uint256 public minQueueDeposit; IERC20 public immutable emissionsToken; mapping(address => uint256) public ownerToRollOverQueueIndex; @@ -55,6 +56,7 @@ contract Carousel is VaultV2 { emissionsToken = IERC20(_data.emissionsToken); relayerFee = _data.relayerFee; depositFee = _data.depositFee; + minQueueDeposit = _data.minQueueDeposit; // set epoch 0 to be allways available to deposit into Queue epochExists[0] = true; @@ -85,7 +87,7 @@ contract Carousel is VaultV2 { override(VaultV2) epochIdExists(_id) epochHasNotStarted(_id) - minRequiredDeposit(_assets) + minRequiredDeposit(_assets, _id) nonReentrant { // make sure that epoch exists @@ -103,7 +105,7 @@ contract Carousel is VaultV2 { external payable override(VaultV2) - minRequiredDeposit(msg.value) + minRequiredDeposit(msg.value, _id) epochIdExists(_id) epochHasNotStarted(_id) nonReentrant @@ -240,7 +242,7 @@ contract Carousel is VaultV2 { uint256 _epochId, uint256 _assets, address _receiver - ) public epochIdExists(_epochId) minRequiredDeposit(_assets) { + ) public epochIdExists(_epochId) minRequiredDeposit(_assets, _epochId) { // check if sender is approved by owner if ( msg.sender != _receiver && @@ -332,16 +334,26 @@ contract Carousel is VaultV2 { while ((length - _operations) <= i) { // this loop impelements FILO (first in last out) stack to reduce gas cost and improve code readability // changing it to FIFO (first in first out) would require more code changes and would be more expensive + // @note non neglectable mint deposit creates barriers for attackers to DDOS the queue + + uint256 assetsToDeposit = queue[i].assets; + + if (depositFee > 0) { + (uint256 feeAmount, uint256 assetsAfterFee) = getEpochDepositFee(_epochId, assetsToDeposit); + assetsToDeposit = assetsAfterFee; + _asset().safeTransfer(treasury, feeAmount); + } + _mintShares( queue[i].receiver, _epochId, - queue[i].assets - relayerFee + assetsToDeposit - relayerFee ); emit Deposit( msg.sender, queue[i].receiver, _epochId, - queue[i].assets - relayerFee + assetsToDeposit - relayerFee ); depositQueue.pop(); if (i == 0) break; @@ -483,14 +495,8 @@ contract Carousel is VaultV2 { uint256 assetsToDeposit = _assets; if (depositFee > 0) { - (uint256 maxX, , uint256 minX) = getEpochConfig(_id); - // deposit fee is calcualted linearly between time of epoch creation and epoch starting (deposit window) - // this is because late depositors have an informational advantage - uint256 fee = _calculateFeePercent(int256(minX), int256(maxX)); - // min minRequiredDeposit modifier ensures that _assets has high enough value to not devide by 0 - // 0.5% = multiply by 10000 then divide by 50 - uint256 feeAmount = _assets.mulDivDown(fee, 10000); - assetsToDeposit = _assets - feeAmount; + (uint256 feeAmount, uint256 assetsAfterFee) = getEpochDepositFee(_id, _assets); + assetsToDeposit = assetsAfterFee; _asset().safeTransfer(treasury, feeAmount); } @@ -628,6 +634,27 @@ contract Carousel is VaultV2 { return ownerToRollOverQueueIndex[_owner] - 1; } + /** @notice retruns deposit fee at this time + * @param _id epoch id + * @param _assets amount of assets + * @return feeAmount fee amount + * @return _assetsAfterFee assets after fee + */ + function getEpochDepositFee(uint256 _id, uint256 _assets) + public + view + returns (uint256 feeAmount, uint256 _assetsAfterFee) + { + (uint256 maxX, , uint256 minX) = getEpochConfig(_id); + // deposit fee is calcualted linearly between time of epoch creation and epoch starting (deposit window) + // this is because late depositors have an informational advantage + uint256 fee = _calculateFeePercent(int256(minX), int256(maxX)); + // min minRequiredDeposit modifier ensures that _assets has high enough value to not devide by 0 + // 0.5% = multiply by 10000 then divide by 50 + feeAmount = _assets.mulDivDown(fee, 10000); + _assetsAfterFee = _assets - feeAmount; + } + /** @notice returns the emissions to withdraw * @param _id epoch id * @param _assets amount of assets to withdraw @@ -733,6 +760,7 @@ contract Carousel is VaultV2 { address emissionsToken; uint256 relayerFee; uint256 depositFee; + uint256 minQueueDeposit; } /*////////////////////////////////////////////////////////////// @@ -742,8 +770,8 @@ contract Carousel is VaultV2 { /** @notice checks if deposit is greater than relayer fee * @param _assets amount of assets to deposit */ - modifier minRequiredDeposit(uint256 _assets) { - if (_assets < relayerFee) revert MinDeposit(); + modifier minRequiredDeposit(uint256 _assets, uint256 _epochId) { + if (_epochId == 0 && _assets < minQueueDeposit) revert MinDeposit(); _; } diff --git a/src/v2/Carousel/CarouselFactory.sol b/src/v2/Carousel/CarouselFactory.sol index dc557a1c..57f343b8 100644 --- a/src/v2/Carousel/CarouselFactory.sol +++ b/src/v2/Carousel/CarouselFactory.sol @@ -77,7 +77,8 @@ contract CarouselFactory is VaultFactoryV2 { treasury, address(emissionsToken), _marketCalldata.relayerFee, - _marketCalldata.depositFee + _marketCalldata.depositFee, + _marketCalldata.minQueueDeposit ) ); @@ -95,7 +96,8 @@ contract CarouselFactory is VaultFactoryV2 { treasury, address(emissionsToken), _marketCalldata.relayerFee, - _marketCalldata.depositFee + _marketCalldata.depositFee, + _marketCalldata.minQueueDeposit ) ); @@ -212,6 +214,7 @@ contract CarouselFactory is VaultFactoryV2 { address controller; uint256 relayerFee; uint256 depositFee; + uint256 minQueueDeposit; } /*////////////////////////////////////////////////////////////// diff --git a/src/v2/libraries/CarouselCreator.sol b/src/v2/libraries/CarouselCreator.sol index 6dfb4eb9..ead966a3 100644 --- a/src/v2/libraries/CarouselCreator.sol +++ b/src/v2/libraries/CarouselCreator.sol @@ -16,6 +16,7 @@ library CarouselCreator { address emissionsToken; uint256 relayerFee; uint256 depositFee; + uint256 minQueueDeposit; } function createCarousel(CarouselMarketConfiguration memory _marketConfig) @@ -37,7 +38,8 @@ library CarouselCreator { _marketConfig.treasury, _marketConfig.emissionsToken, _marketConfig.relayerFee, - _marketConfig.depositFee + _marketConfig.depositFee, + _marketConfig.minQueueDeposit ) ) ); diff --git a/test/V2/Carousel/CarouselFactoryTest.t.sol b/test/V2/Carousel/CarouselFactoryTest.t.sol index d211d194..55cafce8 100644 --- a/test/V2/Carousel/CarouselFactoryTest.t.sol +++ b/test/V2/Carousel/CarouselFactoryTest.t.sol @@ -60,7 +60,8 @@ contract CarouselFactoryTest is Helper { symbol, controller, relayerFee, - depositFee + depositFee, + 1 ether ) ); @@ -266,7 +267,8 @@ contract CarouselFactoryTest is Helper { symbol, controller, relayerFee, - depositFee) + depositFee, + 1 ether) ); } diff --git a/test/V2/Carousel/CarouselTest.t.sol b/test/V2/Carousel/CarouselTest.t.sol index 6915347a..45cce350 100644 --- a/test/V2/Carousel/CarouselTest.t.sol +++ b/test/V2/Carousel/CarouselTest.t.sol @@ -44,7 +44,8 @@ contract CarouselTest is Helper { TREASURY, emissionsToken, relayerFee, - depositFee + depositFee, + 1 ether ) ); diff --git a/test/V2/Helper.sol b/test/V2/Helper.sol index db1d8153..e0b1ccaa 100644 --- a/test/V2/Helper.sol +++ b/test/V2/Helper.sol @@ -7,12 +7,12 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract Helper is Test { uint256 public constant STRIKE = 1000000000000000000; - uint256 public constant COLLATERAL_MINUS_FEES = 21989999998407999999; - uint256 public constant COLLATERAL_MINUS_FEES_DIV10 = 2198999999840799999; + uint256 public constant COLLATERAL_MINUS_FEES = 21989999998398551453; + uint256 public constant COLLATERAL_MINUS_FEES_DIV10 = 2198999999839855145; uint256 public constant NEXT_COLLATERAL_MINUS_FEES = 21827317001456829250; - uint256 public constant USER1_EMISSIONS_AFTER_WITHDRAW = 1096380172807730660741; - uint256 public constant USER2_EMISSIONS_AFTER_WITHDRAW = 96380172807730660741; - uint256 public constant USER_AMOUNT_AFTER_WITHDRAW = 13112658495641799945; + uint256 public constant USER1_EMISSIONS_AFTER_WITHDRAW = 1096655439903230405185; + uint256 public constant USER2_EMISSIONS_AFTER_WITHDRAW = 96655439903230405185; + uint256 public constant USER_AMOUNT_AFTER_WITHDRAW = 13112658495640855090; address public constant ADMIN = address(0x1); address public constant WETH = address(0x888); address public constant TREASURY = address(0x777); diff --git a/test/V2/e2e/EndToEndCarouselTest.t.sol b/test/V2/e2e/EndToEndCarouselTest.t.sol index 03921492..1644b57b 100644 --- a/test/V2/e2e/EndToEndCarouselTest.t.sol +++ b/test/V2/e2e/EndToEndCarouselTest.t.sol @@ -81,7 +81,8 @@ contract EndToEndCarouselTest is Helper { symbol, address(controller), relayerFee, - depositFee) + depositFee, + 1 ether) ); // deploy epoch @@ -168,13 +169,16 @@ contract EndToEndCarouselTest is Helper { Carousel(collateral).mintDepositInQueue(epochId, collateralQueueLength); Carousel(premium).mintDepositInQueue(epochId, premiumQueueLength); + (,uint256 collatBalanceAfterFee) = Carousel(collateral).getEpochDepositFee(epochId, 10 ether); + (,uint256 premiumBalanceAfterFee) = Carousel(premium).getEpochDepositFee(epochId, 2 ether); + //assert balance and emissions - assertEq(Carousel(collateral).balanceOf(USER, epochId), 10 ether - relayerFee); - assertEq(Carousel(collateral).balanceOfEmissions(USER, epochId), 10 ether - relayerFee); - assertEq(Carousel(collateral).balanceOf(USER2, epochId), 10 ether - relayerFee); - assertEq(Carousel(collateral).balanceOfEmissions(USER2, epochId), 10 ether - relayerFee); - assertEq(Carousel(premium).balanceOf(USER, epochId), 2 ether - relayerFee); - assertEq(Carousel(premium).balanceOfEmissions(USER, epochId), 2 ether - relayerFee); + assertEq(Carousel(collateral).balanceOf(USER, epochId), collatBalanceAfterFee - relayerFee); + assertEq(Carousel(collateral).balanceOfEmissions(USER, epochId), collatBalanceAfterFee - relayerFee); + assertEq(Carousel(collateral).balanceOf(USER2, epochId), collatBalanceAfterFee - relayerFee); + assertEq(Carousel(collateral).balanceOfEmissions(USER2, epochId), collatBalanceAfterFee - relayerFee); + assertEq(Carousel(premium).balanceOf(USER, epochId), premiumBalanceAfterFee - relayerFee); + assertEq(Carousel(premium).balanceOfEmissions(USER, epochId), premiumBalanceAfterFee - relayerFee); assertEq(Carousel(premium).balanceOf(USER2, epochId), 0); assertEq(Carousel(premium).balanceOfEmissions(USER2, epochId), 0); From e8fdd8578190424e8ad1036b2e49ecd4e3388ea1 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Fri, 7 Apr 2023 15:05:15 +0200 Subject: [PATCH 04/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/72 --- src/v2/Carousel/Carousel.sol | 165 ++++++++++++++++--------- src/v2/Carousel/CarouselFactory.sol | 9 ++ src/v2/interfaces/ICarousel.sol | 2 + test/V2/e2e/EndToEndCarouselTest.t.sol | 31 +++-- 4 files changed, 143 insertions(+), 64 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index 09ce2866..9682a988 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -251,11 +251,11 @@ contract Carousel is VaultV2 { // check if user has enough balance if (balanceOf(_receiver, _epochId) < _assets) revert InsufficientBalance(); - + // check if user has already queued up a rollover - if (ownerToRollOverQueueIndex[_receiver] != 0) { - // if so, update the queue + if (isEnlistedInRolloverQueue(_receiver)) { uint256 index = getRolloverIndex(_receiver); + // if so, update the queue rolloverQueue[index].assets = _assets; rolloverQueue[index].epochId = _epochId; } else { @@ -268,6 +268,7 @@ contract Carousel is VaultV2 { }) ); } + // index will allways be higher than 0 ownerToRollOverQueueIndex[_receiver] = rolloverQueue.length; emit RolloverQueued(_receiver, _assets, _epochId); @@ -277,33 +278,25 @@ contract Carousel is VaultV2 { @param _owner address that is delisting from rollover queue */ function delistInRollover(address _owner) public { - // check if user has already queued up a rollover - if (ownerToRollOverQueueIndex[_owner] == 0) revert NoRolloverQueued(); + // @note + // its not possible for users to delete the QueueItem from the array because + // during rollover, earlier users in rollover queue, can grief attack later users by deleting their queue item + // instead we just set the assets to 0 and the epochId to 0 as a flag to indicate that the user is no longer in the queue + + + // check if user is enlisted in rollover queue + if (!isEnlistedInRolloverQueue(_owner)) revert NoRolloverQueued(); // check if sender is approved by owner if ( msg.sender != _owner && isApprovedForAll(_owner, msg.sender) == false ) revert OwnerDidNotAuthorize(msg.sender, _owner); - // swich the last item in the queue with the item to be removed + // set assets to 0 but keep the queue item uint256 index = getRolloverIndex(_owner); - uint256 length = rolloverQueue.length; - if (index == length - 1) { - // if only one item in queue - rolloverQueue.pop(); - delete ownerToRollOverQueueIndex[_owner]; - } else { - // overwrite the item to be removed with the last item in the queue - rolloverQueue[index] = rolloverQueue[length - 1]; - // remove the last item in the queue - rolloverQueue.pop(); - // update the index of prev last user ( mapping index is allways array index + 1) - ownerToRollOverQueueIndex[rolloverQueue[index].receiver] = - index + - 1; - // remove receiver from index mapping - delete ownerToRollOverQueueIndex[_owner]; - } + rolloverQueue[index].assets = 0; + rolloverQueue[index].epochId = 0; + } /** @notice mints deposit in rollover queue @@ -334,7 +327,7 @@ contract Carousel is VaultV2 { while ((length - _operations) <= i) { // this loop impelements FILO (first in last out) stack to reduce gas cost and improve code readability // changing it to FIFO (first in first out) would require more code changes and would be more expensive - // @note non neglectable mint deposit creates barriers for attackers to DDOS the queue + // @note non neglectable min-deposit creates barriers for attackers to DDOS the queue uint256 assetsToDeposit = queue[i].assets; @@ -378,7 +371,7 @@ contract Carousel is VaultV2 { nonReentrant { // epoch has not started - // dont allow minting if epochId is 0 + // dont allow rollover if epochId is 0 if (_epochId == 0) revert InvalidEpochId(); uint256 length = rolloverQueue.length; @@ -404,8 +397,8 @@ contract Carousel is VaultV2 { uint256 executions = 0; while ((index - prevIndex) < (_operations)) { - // only roll over if last epoch is resolved - if (epochResolved[queue[index].epochId]) { + // only roll over if last epoch is resolved and user rollover position is valid + if (epochResolved[queue[index].epochId] && queue[index].assets > 0) { uint256 entitledAmount = previewWithdraw( queue[index].epochId, queue[index].assets @@ -512,29 +505,6 @@ contract Carousel is VaultV2 { } } - /** - * @notice calculates fee percent based on time - * @param minX min x value - * @param maxX max x value - */ - function _calculateFeePercent(int256 minX, int256 maxX) - internal - view - returns (uint256 _y) - { - /** - * Two Point Form - * https://www.cuemath.com/geometry/two-point-form/ - * https://ethereum.stackexchange.com/a/143172 - */ - // minY will always be 0 thats why is (maxY - minY) shorten to maxY - int256 maxY = int256(depositFee) * int256(FixedPointMathLib.WAD); - _y = uint256( // cast to uint256 - ((((maxY) / (maxX - minX)) * (int256(block.timestamp) - maxX)) + - maxY) / (int256(FixedPointMathLib.WAD)) // two point math // scale down - ); - } - /** @notice mints shares of vault for user @param to address of receiver @param id epoch id @@ -622,16 +592,65 @@ contract Carousel is VaultV2 { depositFee = _depositFee; } + /** @notice cleans up rollover queue + * @dev this function can only be called if there is no active deposit window + * @param _addressesToDelist addresses to delist + */ + function cleanUpRolloverQueue(address[] memory _addressesToDelist ) external onlyFactory epochHasStarted(epochs[epochs.length - 1]) { + // check that there is no active deposit window; + for (uint256 i = 0; i < _addressesToDelist.length; i++) { + address owner = _addressesToDelist[i]; + uint256 index = ownerToRollOverQueueIndex[owner]; + if (index == 0) continue; + uint256 queueIndex = index - 1; + if (rolloverQueue[queueIndex].assets == 0) { + // overwrite the item to be removed with the last item in the queue + rolloverQueue[queueIndex] = rolloverQueue[rolloverQueue.length - 1]; + // remove the last item in the queue + rolloverQueue.pop(); + // update the index of prev last user ( mapping index is allways array index + 1) + ownerToRollOverQueueIndex[rolloverQueue[queueIndex].receiver] = queueIndex + 1; + // remove receiver from index mapping + delete ownerToRollOverQueueIndex[owner]; + } + } + } + /*/////////////////////////////////////////////////////////////// Getter Functions //////////////////////////////////////////////////////////////*/ + /** + * @notice calculates fee percent based on time + * @param minX min x value + * @param maxX max x value + */ + function calculateFeePercent(int256 minX, int256 maxX) + public + view + returns (uint256 _y) + { + /** + * Two Point Form + * https://www.cuemath.com/geometry/two-point-form/ + * https://ethereum.stackexchange.com/a/143172 + */ + // minY will always be 0 thats why is (maxY - minY) shorten to maxY + int256 maxY = int256(depositFee) * int256(FixedPointMathLib.WAD); + _y = uint256( // cast to uint256 + ((((maxY) / (maxX - minX)) * (int256(block.timestamp) - maxX)) + + maxY) / (int256(FixedPointMathLib.WAD)) // two point math // scale down + ); + } + + /** @notice returns the rollover index + * @dev will revert if user is not in rollover queue * @param _owner address of the owner * @return rollover index */ function getRolloverIndex(address _owner) public view returns (uint256) { - return ownerToRollOverQueueIndex[_owner] - 1; + return ownerToRollOverQueueIndex[_owner] - 1; } /** @notice retruns deposit fee at this time @@ -648,7 +667,7 @@ contract Carousel is VaultV2 { (uint256 maxX, , uint256 minX) = getEpochConfig(_id); // deposit fee is calcualted linearly between time of epoch creation and epoch starting (deposit window) // this is because late depositors have an informational advantage - uint256 fee = _calculateFeePercent(int256(minX), int256(maxX)); + uint256 fee = calculateFeePercent(int256(minX), int256(maxX)); // min minRequiredDeposit modifier ensures that _assets has high enough value to not devide by 0 // 0.5% = multiply by 10000 then divide by 50 feeAmount = _assets.mulDivDown(fee, 10000); @@ -703,18 +722,52 @@ contract Carousel is VaultV2 { } } + function getRolloverQueueItem(uint256 _index) + public + view + returns ( + address receiver, + uint256 assets, + uint256 epochId + ) + { + receiver = rolloverQueue[_index].receiver; + assets = rolloverQueue[_index].assets; + epochId = rolloverQueue[_index].epochId; + } + /** @notice returns users rollover balance and epoch which is rolling over * @param _owner address of the user * @return balance balance of the user * @return epochId epoch id */ - function getRolloverBalance(address _owner) + function getRolloverPosition(address _owner) public view returns (uint256 balance, uint256 epochId) { - balance = rolloverQueue[getRolloverIndex(_owner)].assets; - epochId = rolloverQueue[getRolloverIndex(_owner)].epochId; + if (!isEnlistedInRolloverQueue(_owner)) { + return (0, 0); + } + uint256 index = getRolloverIndex(_owner); + balance = rolloverQueue[index].assets; + epochId = rolloverQueue[index].epochId; + } + + + /** @notice returns is user is enlisted in the rollover queue + * @param _owner address of the user + * @return bool is user enlisted in the rollover queue + */ + function isEnlistedInRolloverQueue(address _owner) + public + view + returns (bool) + { + if(ownerToRollOverQueueIndex[_owner] == 0) { + return false; + } + return rolloverQueue[getRolloverIndex(_owner)].assets != 0; } /** @notice returns the total value locked in the deposit queue @@ -785,7 +838,7 @@ contract Carousel is VaultV2 { uint256 _epochId, uint256 _assets ) { - if (ownerToRollOverQueueIndex[_receiver] != 0) { + if (isEnlistedInRolloverQueue(_receiver)) { QueueItem memory item = rolloverQueue[getRolloverIndex(_receiver)]; if ( item.epochId == _epochId && diff --git a/src/v2/Carousel/CarouselFactory.sol b/src/v2/Carousel/CarouselFactory.sol index 57f343b8..0fd3e272 100644 --- a/src/v2/Carousel/CarouselFactory.sol +++ b/src/v2/Carousel/CarouselFactory.sol @@ -200,6 +200,15 @@ contract CarouselFactory is VaultFactoryV2 { ); } + // admin function to cleanup rollover queue by passing in array of addresses and vault address + function cleanupRolloverQueue(address[] memory _addresses, address _vault) + public + onlyTimeLocker + { + ICarousel(_vault).cleanupRolloverQueue(_addresses); + } + + /*////////////////////////////////////////////////////////////// STRUCTS //////////////////////////////////////////////////////////////*/ diff --git a/src/v2/interfaces/ICarousel.sol b/src/v2/interfaces/ICarousel.sol index 040c565c..d81edf36 100644 --- a/src/v2/interfaces/ICarousel.sol +++ b/src/v2/interfaces/ICarousel.sol @@ -93,4 +93,6 @@ interface ICarousel { function depositFee() external view returns (uint256); function emissions(uint256 _epochId) external view returns (uint256); + + function cleanupRolloverQueue(address[] memory) external; } diff --git a/test/V2/e2e/EndToEndCarouselTest.t.sol b/test/V2/e2e/EndToEndCarouselTest.t.sol index 1644b57b..d02a79e0 100644 --- a/test/V2/e2e/EndToEndCarouselTest.t.sol +++ b/test/V2/e2e/EndToEndCarouselTest.t.sol @@ -187,6 +187,12 @@ contract EndToEndCarouselTest is Helper { //enlist in rollover for next epoch Carousel(collateral).enlistInRollover(epochId, 8 ether, USER); + bool isEnlisted = Carousel(collateral).isEnlistedInRolloverQueue(USER); + (uint256 enlistedAmount, uint256 id) = Carousel(collateral).getRolloverPosition(USER); + + assertEq(isEnlisted, true); + assertEq(enlistedAmount, 8 ether); + vm.stopPrank(); vm.startPrank(USER2); @@ -254,9 +260,11 @@ contract EndToEndCarouselTest is Helper { uint256 beforeQueueLength = Carousel(collateral).getRolloverQueueLenght(); Carousel(collateral).delistInRollover(USER); - //assert rollover queue length - uint256 afterQueueLength = Carousel(collateral).getRolloverQueueLenght(); - assertEq(afterQueueLength, beforeQueueLength - 1); + //assert delisted rollover position in queue assets are 0 + bool ie = Carousel(collateral).isEnlistedInRolloverQueue(USER); + ( uint256 amountAfterDelisting,) = Carousel(collateral).getRolloverPosition(USER); + assertTrue(!ie); + assertEq(amountAfterDelisting, 0); //assert balance in next epoch uint256 balanceInNextEpoch = Carousel(collateral).balanceOf(USER, nextEpochId); @@ -270,20 +278,27 @@ contract EndToEndCarouselTest is Helper { vm.stopPrank(); + // cleanup queue from delisted users + vm.startPrank(address(factory)); + uint256 beforeQueueLength2 = Carousel(collateral).getRolloverQueueLenght(); + assertEq(beforeQueueLength2, 2); + address[] memory addressesToDelist = new address[](1); + addressesToDelist[0] = USER; + Carousel(collateral).cleanUpRolloverQueue(addressesToDelist); + uint256 afterQueueLength2 = Carousel(collateral).getRolloverQueueLenght(); + assertEq(afterQueueLength2, 1); + vm.stopPrank(); + //withdraw USER2 vm.startPrank(USER2); - //assert rollover index + //assert rollover index, should be 0 since USER1 lising was cleaned up assertTrue(Carousel(collateral).getRolloverIndex(USER2) == 0); //delist rollover beforeQueueLength = Carousel(collateral).getRolloverQueueLenght(); Carousel(collateral).delistInRollover(USER2); - //assert rollover queue length - afterQueueLength = Carousel(collateral).getRolloverQueueLenght(); - assertEq(afterQueueLength, beforeQueueLength - 1); - //assert balance in next epoch balanceInNextEpoch = Carousel(collateral).balanceOf(USER2, nextEpochId); From 57bf4913bbffda6d0c265c5cd6caf516f4a375f1 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Fri, 7 Apr 2023 15:10:37 +0200 Subject: [PATCH 05/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/2 --- src/v2/Carousel/Carousel.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index 9682a988..714650df 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -267,10 +267,10 @@ contract Carousel is VaultV2 { epochId: _epochId }) ); + // index will allways be higher than 0 + ownerToRollOverQueueIndex[_receiver] = rolloverQueue.length; } - // index will allways be higher than 0 - ownerToRollOverQueueIndex[_receiver] = rolloverQueue.length; - + emit RolloverQueued(_receiver, _assets, _epochId); } From 0efdff3b5f87027636f62470b7730e6f216c4c75 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Fri, 7 Apr 2023 15:43:17 +0200 Subject: [PATCH 06/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/505 --- src/v2/Carousel/CarouselFactory.sol | 26 +++++++++++++++++++++++- src/v2/VaultFactoryV2.sol | 31 +++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/v2/Carousel/CarouselFactory.sol b/src/v2/Carousel/CarouselFactory.sol index 0fd3e272..79a6515c 100644 --- a/src/v2/Carousel/CarouselFactory.sol +++ b/src/v2/Carousel/CarouselFactory.sol @@ -121,6 +121,19 @@ contract CarouselFactory is VaultFactoryV2 { return (premium, collateral, marketId); } + + function createNewMarket(MarketConfigurationCalldata memory) + override + external + returns ( + address , + address , + uint256 + ) + { + revert(); + } + /** @notice Function to create a new epoch with emissions @param _marketId uint256 of the marketId @param _epochBegin uint40 of the epoch begin @@ -140,7 +153,7 @@ contract CarouselFactory is VaultFactoryV2 { uint256 _collatEmissions ) public returns (uint256 epochId, address[2] memory vaults) { // no need for onlyOwner modifier as createEpoch already has modifier - (epochId, vaults) = createEpoch( + (epochId, vaults) = _createEpoch( _marketId, _epochBegin, _epochEnd, @@ -154,6 +167,17 @@ contract CarouselFactory is VaultFactoryV2 { ICarousel(vaults[1]).setEmissions(epochId, _collatEmissions); } + // to prevent the creation of epochs without emissions + // this function is not used + function createEpoch( + uint256 /*_marketId*/, + uint40 /*_epochBegin*/, + uint40 /*_epochEnd*/, + uint16 /*_withdrawalFee*/ + ) override public returns (uint256, address[2] memory) { + revert(); + } + /*////////////////////////////////////////////////////////////// ADMIN FUNCTIONS //////////////////////////////////////////////////////////////*/ diff --git a/src/v2/VaultFactoryV2.sol b/src/v2/VaultFactoryV2.sol index 751d5fe5..4ae19142 100644 --- a/src/v2/VaultFactoryV2.sol +++ b/src/v2/VaultFactoryV2.sol @@ -56,6 +56,7 @@ contract VaultFactoryV2 is Ownable { @return marketId uint256 of the marketId */ function createNewMarket(MarketConfigurationCalldata memory _marketCalldata) + virtual external onlyOwner returns ( @@ -63,6 +64,17 @@ contract VaultFactoryV2 is Ownable { address collateral, uint256 marketId ) + { + return _createNewMarket(_marketCalldata); + } + + function _createNewMarket(MarketConfigurationCalldata memory _marketCalldata) + internal + returns ( + address premium, + address collateral, + uint256 marketId + ) { if (!controllers[_marketCalldata.controller]) revert ControllerNotSet(); if (_marketCalldata.token == address(0)) revert AddressZero(); @@ -127,6 +139,7 @@ contract VaultFactoryV2 is Ownable { return (premium, collateral, marketId); } + /** @notice Function set epoch for market, @param _marketId uint256 of the market index to create more assets in @@ -139,7 +152,22 @@ contract VaultFactoryV2 is Ownable { uint40 _epochBegin, uint40 _epochEnd, uint16 _withdrawalFee - ) public onlyOwner returns (uint256 epochId, address[2] memory vaults) { + ) virtual public onlyOwner returns (uint256 epochId, address[2] memory vaults) { + return + _createEpoch( + _marketId, + _epochBegin, + _epochEnd, + _withdrawalFee + ); + } + + function _createEpoch( + uint256 _marketId, + uint40 _epochBegin, + uint40 _epochEnd, + uint16 _withdrawalFee + ) internal returns (uint256 epochId, address[2] memory vaults) { vaults = marketIdToVaults[_marketId]; if (vaults[0] == address(0) || vaults[1] == address(0)) { @@ -167,7 +195,6 @@ contract VaultFactoryV2 is Ownable { ) ); } - /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ From 2ba5a0311c7e2395352caaf15757ebe773d19314 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Fri, 7 Apr 2023 16:09:42 +0200 Subject: [PATCH 07/31] https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/480 --- test/legacy_v1/Vault.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/legacy_v1/Vault.sol b/test/legacy_v1/Vault.sol index 192ebb43..8804ee5d 100644 --- a/test/legacy_v1/Vault.sol +++ b/test/legacy_v1/Vault.sol @@ -84,7 +84,7 @@ contract Vault is SemiFungibleVault, ReentrancyGuard { /** @notice You can only call functions that use this modifier before the current epoch has started */ modifier epochHasNotStarted(uint256 id) { - if (block.timestamp > idEpochBegin[id]) revert EpochAlreadyStarted(); + if (block.timestamp >= idEpochBegin[id]) revert EpochAlreadyStarted(); _; } From 6fd592e50eb2400f095ca903f723956b7c06c240 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 10 Apr 2023 12:16:31 +0200 Subject: [PATCH 08/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/435 --- src/v2/VaultFactoryV2.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v2/VaultFactoryV2.sol b/src/v2/VaultFactoryV2.sol index 4ae19142..e3005106 100644 --- a/src/v2/VaultFactoryV2.sol +++ b/src/v2/VaultFactoryV2.sol @@ -266,8 +266,8 @@ contract VaultFactoryV2 is Ownable { IVaultV2(vaults[0]).whiteListAddress(_treasury); IVaultV2(vaults[1]).whiteListAddress(_treasury); - IVaultV2(vaults[0]).setTreasury(treasury); - IVaultV2(vaults[1]).setTreasury(treasury); + IVaultV2(vaults[0]).setTreasury(_treasury); + IVaultV2(vaults[1]).setTreasury(_treasury); emit AddressWhitelisted(_treasury, _marketId); } From 4221a60eb54b1ac0dc8ccf29403978c9513fac48 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 10 Apr 2023 13:42:20 +0200 Subject: [PATCH 09/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/418 --- src/v2/Carousel/Carousel.sol | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index 714650df..310e5461 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -397,8 +397,16 @@ contract Carousel is VaultV2 { uint256 executions = 0; while ((index - prevIndex) < (_operations)) { + + // skip the rollover for the user if the assets cannot cover the relayer fee instead of revert. + if (queue[index].assets < relayerFee) { + index++; + continue; + } + // only roll over if last epoch is resolved and user rollover position is valid if (epochResolved[queue[index].epochId] && queue[index].assets > 0) { + uint256 entitledAmount = previewWithdraw( queue[index].epochId, queue[index].assets @@ -408,12 +416,7 @@ contract Carousel is VaultV2 { uint256 diff = entitledAmount - queue[index].assets; // get diff amount in assets uint256 diffInAssets = diff.mulDivUp(finalTVL[queue[index].epochId], claimTVL[queue[index].epochId]); - // skip the rollover for the user if the assets cannot cover the relayer fee instead of revert. - if (queue[index].assets < relayerFee) { - index++; - continue; - } - + uint256 originalDepositValue = queue[index].assets - diffInAssets; // @note we know shares were locked up to this point _burn( From 88430852ddf2c0def42ad3132e5c12df86da096a Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 10 Apr 2023 13:49:01 +0200 Subject: [PATCH 10/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/387 --- src/v2/TimeLock.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/v2/TimeLock.sol b/src/v2/TimeLock.sol index 145ed35f..c882d0d8 100644 --- a/src/v2/TimeLock.sol +++ b/src/v2/TimeLock.sol @@ -77,7 +77,7 @@ contract TimeLock { string calldata _func, bytes calldata _data, uint256 _timestamp - ) external onlyOwner returns (bytes memory) { + ) external payable onlyOwner returns (bytes memory) { bytes32 txId = getTxId(_target, _value, _func, _data, _timestamp); //check tx id queued @@ -109,6 +109,9 @@ contract TimeLock { data = _data; } + if(msg.value != _value) { + revert ValueNotMatchError(msg.value, _value); + } // call target (bool ok, bytes memory res) = _target.call{value: _value}(data); if (!ok) { @@ -188,6 +191,7 @@ contract TimeLock { error TimestampExpiredError(uint256 blocktimestamp, uint256 timestamp); error TxFailedError(string func); error AddressZero(); + error ValueNotMatchError(uint256 msgValue, uint256 value); /** @notice queues transaction when emitted @param txId unique id of the transaction From 39bb0b53d48ca2266a7450701d28b0263ccb287f Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 10 Apr 2023 14:07:45 +0200 Subject: [PATCH 11/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/300 --- src/v2/Carousel/CarouselFactory.sol | 2 +- src/v2/VaultFactoryV2.sol | 41 +++++++++++++++++++--- test/V2/Carousel/CarouselFactoryTest.t.sol | 2 +- test/V2/FactoryV2Test.t.sol | 2 +- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/v2/Carousel/CarouselFactory.sol b/src/v2/Carousel/CarouselFactory.sol index 79a6515c..492d05bd 100644 --- a/src/v2/Carousel/CarouselFactory.sol +++ b/src/v2/Carousel/CarouselFactory.sol @@ -59,7 +59,7 @@ contract CarouselFactory is VaultFactoryV2 { tokenToOracle[_marketCalldata.token] = _marketCalldata.oracle; } - marketId = getMarketId(_marketCalldata.token, _marketCalldata.strike); + marketId = getMarketId(_marketCalldata.token, _marketCalldata.strike, _marketCalldata.underlyingAsset); if (marketIdToVaults[marketId][0] != address(0)) revert MarketAlreadyExists(); diff --git a/src/v2/VaultFactoryV2.sol b/src/v2/VaultFactoryV2.sol index e3005106..57983050 100644 --- a/src/v2/VaultFactoryV2.sol +++ b/src/v2/VaultFactoryV2.sol @@ -22,6 +22,7 @@ contract VaultFactoryV2 is Ownable { mapping(uint256 => address[2]) public marketIdToVaults; //[0] premium and [1] collateral vault mapping(uint256 => uint256[]) public marketIdToEpochs; //all epochs in the market + mapping(uint256 => MarketInfo) public marketIdInfo; // marketId configuration mapping(uint256 => uint16) public epochFee; // epochId to fee mapping(address => address) public tokenToOracle; //token address to respective oracle smart contract address mapping(address => bool) public controllers; @@ -85,7 +86,13 @@ contract VaultFactoryV2 is Ownable { tokenToOracle[_marketCalldata.token] = _marketCalldata.oracle; } - marketId = getMarketId(_marketCalldata.token, _marketCalldata.strike); + marketId = getMarketId(_marketCalldata.token, _marketCalldata.strike, _marketCalldata.underlyingAsset); + marketIdInfo[marketId] = MarketInfo( + _marketCalldata.token, + _marketCalldata.strike, + _marketCalldata.underlyingAsset + ); + if (marketIdToVaults[marketId][0] != address(0)) revert MarketAlreadyExists(); @@ -395,16 +402,33 @@ contract VaultFactoryV2 is Ownable { /** @notice Function to compute the marketId from a token and a strike price - @param token Address of the token - @param strikePrice uint256 of the strike price + @param _token Address of the token + @param _strikePrice uint256 of the strike price + @param _underlying Address of the underlying @return marketId uint256 of the marketId */ - function getMarketId(address token, uint256 strikePrice) + function getMarketId(address _token, uint256 _strikePrice, address _underlying) public pure returns (uint256 marketId) { - return uint256(keccak256(abi.encodePacked(token, strikePrice))); + return uint256(keccak256(abi.encodePacked(_token, _strikePrice, _underlying))); + } + + + // get marketInfo + function getMarketInfo(uint256 _marketId) + public + view + returns ( + address token, + uint256 strike, + address underlyingAsset + ) + { + token = marketIdInfo[_marketId].token; + strike = marketIdInfo[_marketId].strike; + underlyingAsset = marketIdInfo[_marketId].underlyingAsset; } /** @@ -448,6 +472,13 @@ contract VaultFactoryV2 is Ownable { IVaultV2 collateral; } + + struct MarketInfo { + address token; + uint256 strike; + address underlyingAsset; + } + /*////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ diff --git a/test/V2/Carousel/CarouselFactoryTest.t.sol b/test/V2/Carousel/CarouselFactoryTest.t.sol index 55cafce8..302a9f83 100644 --- a/test/V2/Carousel/CarouselFactoryTest.t.sol +++ b/test/V2/Carousel/CarouselFactoryTest.t.sol @@ -72,7 +72,7 @@ contract CarouselFactoryTest is Helper { // test oracle is set assertTrue(factory.tokenToOracle(token) == oracle); - assertEq(marketId, factory.getMarketId(token, strike)); + assertEq(marketId, factory.getMarketId(token, strike, underlying)); // test if counterparty is set assertEq(IVaultV2(premium).counterPartyVault(), collateral); diff --git a/test/V2/FactoryV2Test.t.sol b/test/V2/FactoryV2Test.t.sol index 79b3a0a3..c7939a99 100644 --- a/test/V2/FactoryV2Test.t.sol +++ b/test/V2/FactoryV2Test.t.sol @@ -160,7 +160,7 @@ contract FactoryV2Test is Helper { // test oracle is set assertTrue(factory.tokenToOracle(token) == oracle); - assertEq(marketId, factory.getMarketId(token, strike)); + assertEq(marketId, factory.getMarketId(token, strike, underlying)); // test if counterparty is set assertEq(IVaultV2(premium).counterPartyVault(), collateral); From 638a1819ccd6b7ad26d8c6278a3c3cb562f6f552 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 10 Apr 2023 17:49:42 +0200 Subject: [PATCH 12/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/293 --- src/v2/Carousel/Carousel.sol | 46 +++++++++++++++++++------- test/V2/Carousel/CarouselTest.t.sol | 30 ++++++++--------- test/V2/Helper.sol | 8 ++--- test/V2/e2e/EndToEndCarouselTest.t.sol | 8 ++--- 4 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index 310e5461..51909d2b 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -398,12 +398,6 @@ contract Carousel is VaultV2 { while ((index - prevIndex) < (_operations)) { - // skip the rollover for the user if the assets cannot cover the relayer fee instead of revert. - if (queue[index].assets < relayerFee) { - index++; - continue; - } - // only roll over if last epoch is resolved and user rollover position is valid if (epochResolved[queue[index].epochId] && queue[index].assets > 0) { @@ -411,13 +405,22 @@ contract Carousel is VaultV2 { queue[index].epochId, queue[index].assets ); + // mint only if user won epoch he is rolling over if (entitledAmount > queue[index].assets) { - uint256 diff = entitledAmount - queue[index].assets; - // get diff amount in assets - uint256 diffInAssets = diff.mulDivUp(finalTVL[queue[index].epochId], claimTVL[queue[index].epochId]); - - uint256 originalDepositValue = queue[index].assets - diffInAssets; + // @note previewAmountInShares can only be called if epoch is in profit + uint256 relayerFeeInShares = previewAmountInShares(queue[index].epochId, relayerFee); + + // skip the rollover for the user if the assets cannot cover the relayer fee instead of revert. + if (queue[index].assets < relayerFeeInShares) { + index++; + continue; + } + + // to calculate originalDepositValue get the diff between shares and value of shares + // convert this value amount value back to shares + // subtract from assets + uint256 originalDepositValue = queue[index].assets - previewAmountInShares(queue[index].epochId, (entitledAmount - queue[index].assets)); // @note we know shares were locked up to this point _burn( queue[index].receiver, @@ -447,7 +450,7 @@ contract Carousel is VaultV2 { originalDepositValue, entitledAmount ); - uint256 assetsToMint = queue[index].assets - relayerFee; + uint256 assetsToMint = queue[index].assets - relayerFeeInShares; _mintShares(queue[index].receiver, _epochId, assetsToMint); emit Deposit( msg.sender, @@ -690,6 +693,25 @@ contract Carousel is VaultV2 { entitledAmount = _assets.mulDivDown(emissions[_id], finalTVL[_id]); } + /** @notice returns the emissions to withdraw + * @param _id epoch id + * @param _assets amount of shares + * @return entitledShareAmount amount of emissions to withdraw + */ + function previewAmountInShares(uint256 _id, uint256 _assets) + public + view + returns (uint256 entitledShareAmount) + { + if(claimTVL[_id] != 0) { + entitledShareAmount = _assets.mulDivDown(finalTVL[_id], claimTVL[_id]); + } else { + entitledShareAmount = 0; + } + + } + + /** @notice returns the deposit queue length * @return queue length for the deposit */ diff --git a/test/V2/Carousel/CarouselTest.t.sol b/test/V2/Carousel/CarouselTest.t.sol index 45cce350..e6a6427d 100644 --- a/test/V2/Carousel/CarouselTest.t.sol +++ b/test/V2/Carousel/CarouselTest.t.sol @@ -319,8 +319,6 @@ contract CarouselTest is Helper { .with_key(prevEpoch) .checked_write(1000 ether); - console.log("rollover queue length", vault.getRolloverQueueLenght()); - // get value of prev epoch sahres for user uint256 prevEpochShareValue = vault.previewWithdraw(prevEpoch, vault.balanceOf(USER, prevEpoch)); @@ -337,23 +335,23 @@ contract CarouselTest is Helper { uint256 _relayerFee = (balanceAfter - balanceBefore) / 6; assertEq(_relayerFee, relayerFee); + uint256 relayerFeeInShares = vault.previewAmountInShares(prevEpoch,relayerFee); //@note after rollover, prev value of shares should subtract by original deposit value uint256 prevEpochSharesValueAfterRollover = vault.previewWithdraw(prevEpoch, vault.balanceOf(USER, prevEpoch)); - assertEq(((prevEpochSharesValueAfterRollover >> 1) << 1) , ((prevEpochShareValue - prevEpochUserBalance) >> 1) << 1); // zero out last bit to avoid rounding errors - + assertEq(((prevEpochSharesValueAfterRollover >> 1) << 1) , (((prevEpochShareValue) - (prevEpochUserBalance) - 16) >> 1) << 1); // zero out last bit to avoid rounding errors // check balances - assertEq(vault.balanceOf(USER, _epochId), prevEpochUserBalance - relayerFee); - assertEq(vault.balanceOfEmissions(USER, _epochId), prevEpochUserBalance - relayerFee); - assertEq(vault.balanceOf(USER2, _epochId), prevEpochUserBalance - relayerFee); - assertEq(vault.balanceOfEmissions(USER2, _epochId), prevEpochUserBalance - relayerFee); - assertEq(vault.balanceOf(USER3, _epochId), prevEpochUserBalance - relayerFee); - assertEq(vault.balanceOfEmissions(USER3, _epochId), prevEpochUserBalance - relayerFee); - assertEq(vault.balanceOf(USER4, _epochId), prevEpochUserBalance - relayerFee); - assertEq(vault.balanceOfEmissions(USER4, _epochId), prevEpochUserBalance - relayerFee); - assertEq(vault.balanceOf(USER5, _epochId), prevEpochUserBalance - relayerFee); - assertEq(vault.balanceOfEmissions(USER5, _epochId), prevEpochUserBalance - relayerFee); - assertEq(vault.balanceOf(USER6, _epochId), prevEpochUserBalance - relayerFee); - assertEq(vault.balanceOfEmissions(USER6, _epochId), prevEpochUserBalance - relayerFee); + assertEq(vault.balanceOf(USER, _epochId), prevEpochUserBalance - relayerFeeInShares ); + assertEq(vault.balanceOfEmissions(USER, _epochId), prevEpochUserBalance - relayerFeeInShares); + assertEq(vault.balanceOf(USER2, _epochId), prevEpochUserBalance - relayerFeeInShares); + assertEq(vault.balanceOfEmissions(USER2, _epochId), prevEpochUserBalance - relayerFeeInShares); + assertEq(vault.balanceOf(USER3, _epochId), prevEpochUserBalance - relayerFeeInShares); + assertEq(vault.balanceOfEmissions(USER3, _epochId), prevEpochUserBalance - relayerFeeInShares); + assertEq(vault.balanceOf(USER4, _epochId), prevEpochUserBalance - relayerFeeInShares); + assertEq(vault.balanceOfEmissions(USER4, _epochId), prevEpochUserBalance - relayerFeeInShares); + assertEq(vault.balanceOf(USER5, _epochId), prevEpochUserBalance - relayerFeeInShares); + assertEq(vault.balanceOfEmissions(USER5, _epochId), prevEpochUserBalance - relayerFeeInShares); + assertEq(vault.balanceOf(USER6, _epochId), prevEpochUserBalance - relayerFeeInShares); + assertEq(vault.balanceOfEmissions(USER6, _epochId), prevEpochUserBalance - relayerFeeInShares); } diff --git a/test/V2/Helper.sol b/test/V2/Helper.sol index e0b1ccaa..9732f282 100644 --- a/test/V2/Helper.sol +++ b/test/V2/Helper.sol @@ -9,10 +9,10 @@ contract Helper is Test { uint256 public constant STRIKE = 1000000000000000000; uint256 public constant COLLATERAL_MINUS_FEES = 21989999998398551453; uint256 public constant COLLATERAL_MINUS_FEES_DIV10 = 2198999999839855145; - uint256 public constant NEXT_COLLATERAL_MINUS_FEES = 21827317001456829250; - uint256 public constant USER1_EMISSIONS_AFTER_WITHDRAW = 1096655439903230405185; - uint256 public constant USER2_EMISSIONS_AFTER_WITHDRAW = 96655439903230405185; - uint256 public constant USER_AMOUNT_AFTER_WITHDRAW = 13112658495640855090; + uint256 public constant NEXT_COLLATERAL_MINUS_FEES = 21827317001324992496; + uint256 public constant USER1_EMISSIONS_AFTER_WITHDRAW = 1096655439903230405190; + uint256 public constant USER2_EMISSIONS_AFTER_WITHDRAW = 96655439903230405190; + uint256 public constant USER_AMOUNT_AFTER_WITHDRAW = 13112658495821846450; address public constant ADMIN = address(0x1); address public constant WETH = address(0x888); address public constant TREASURY = address(0x777); diff --git a/test/V2/e2e/EndToEndCarouselTest.t.sol b/test/V2/e2e/EndToEndCarouselTest.t.sol index d02a79e0..75b719c2 100644 --- a/test/V2/e2e/EndToEndCarouselTest.t.sol +++ b/test/V2/e2e/EndToEndCarouselTest.t.sol @@ -269,8 +269,8 @@ contract EndToEndCarouselTest is Helper { //assert balance in next epoch uint256 balanceInNextEpoch = Carousel(collateral).balanceOf(USER, nextEpochId); - //assert rollover minus relayer fee - assertEq(balanceInNextEpoch, 8 ether - relayerFee); + //assert rollover minus relayer fee which is subtracted based on the value of the shares of the prev epoch + assertEq(balanceInNextEpoch, (8 ether - Carousel(collateral).previewAmountInShares(epochId, relayerFee))); //withdraw after rollover Carousel(collateral).withdraw(nextEpochId, balanceInNextEpoch, USER, USER); @@ -302,8 +302,8 @@ contract EndToEndCarouselTest is Helper { //assert balance in next epoch balanceInNextEpoch = Carousel(collateral).balanceOf(USER2, nextEpochId); - //assert rollover minus relayer fee - assertTrue(balanceInNextEpoch == 8 ether - relayerFee); + //assert rollover minus relayer fee which is subtracted based on the value of the shares of the prev epoch + assertTrue(balanceInNextEpoch == 8 ether - Carousel(collateral).previewAmountInShares(epochId, relayerFee)); //withdraw after rollover Carousel(collateral).withdraw(nextEpochId, balanceInNextEpoch, USER2, USER2); From eef2eff30d888d3998336c4a68c2d30de876a5fc Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 10 Apr 2023 19:16:59 +0200 Subject: [PATCH 13/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/208 --- src/v2/Carousel/Carousel.sol | 8 +++--- src/v2/VaultFactoryV2.sol | 27 +------------------ src/v2/VaultV2.sol | 28 +++++++------------- src/v2/interfaces/IVaultFactoryV2.sol | 2 ++ src/v2/interfaces/IVaultV2.sol | 1 - src/v2/libraries/CarouselCreator.sol | 1 - src/v2/libraries/VaultV2Creator.sol | 3 +-- test/V2/Carousel/CarouselTest.t.sol | 5 +++- test/V2/FactoryV2Test.t.sol | 21 --------------- test/V2/VaultV2Test.t.sol | 37 ++++++++------------------- 10 files changed, 31 insertions(+), 102 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index 51909d2b..d968c05f 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -46,8 +46,7 @@ contract Carousel is VaultV2 { _data.tokenURI, _data.token, _data.strike, - _data.controller, - _data.treasury + _data.controller ) { if (_data.relayerFee < 10000) revert RelayerFeeToLow(); @@ -334,7 +333,7 @@ contract Carousel is VaultV2 { if (depositFee > 0) { (uint256 feeAmount, uint256 assetsAfterFee) = getEpochDepositFee(_epochId, assetsToDeposit); assetsToDeposit = assetsAfterFee; - _asset().safeTransfer(treasury, feeAmount); + _asset().safeTransfer(treasury(), feeAmount); } _mintShares( @@ -496,7 +495,7 @@ contract Carousel is VaultV2 { if (depositFee > 0) { (uint256 feeAmount, uint256 assetsAfterFee) = getEpochDepositFee(_id, _assets); assetsToDeposit = assetsAfterFee; - _asset().safeTransfer(treasury, feeAmount); + _asset().safeTransfer(treasury(), feeAmount); } _mintShares(_receiver, _id, assetsToDeposit); @@ -834,7 +833,6 @@ contract Carousel is VaultV2 { address token; uint256 strike; address controller; - address treasury; address emissionsToken; uint256 relayerFee; uint256 depositFee; diff --git a/src/v2/VaultFactoryV2.sol b/src/v2/VaultFactoryV2.sol index 57983050..6327060b 100644 --- a/src/v2/VaultFactoryV2.sol +++ b/src/v2/VaultFactoryV2.sol @@ -236,7 +236,7 @@ contract VaultFactoryV2 is Ownable { /** @notice Function to whitelist controller smart contract, only owner or timelocker can add more controllers. - owner can set controller once, all future controllers must be set by timelocker. + @dev owner can set controller once, all future controllers must be set by timelocker. @param _controller Address of the controller smart contract */ function whitelistController(address _controller) public { @@ -254,31 +254,6 @@ contract VaultFactoryV2 is Ownable { } } - /** - @notice Admin function, whitelists an address on vault for sendTokens function - @param _treasury Treasury address - @param _marketId Target market index - */ - function changeTreasury(uint256 _marketId, address _treasury) - public - onlyTimeLocker - { - if (_treasury == address(0)) revert AddressZero(); - - address[2] memory vaults = marketIdToVaults[_marketId]; - - if (vaults[0] == address(0) || vaults[1] == address(0)) { - revert MarketDoesNotExist(_marketId); - } - - IVaultV2(vaults[0]).whiteListAddress(_treasury); - IVaultV2(vaults[1]).whiteListAddress(_treasury); - IVaultV2(vaults[0]).setTreasury(_treasury); - IVaultV2(vaults[1]).setTreasury(_treasury); - - emit AddressWhitelisted(_treasury, _marketId); - } - /** @notice Admin function, whitelists an address on vault for sendTokens function @param _marketId Target market index diff --git a/src/v2/VaultV2.sol b/src/v2/VaultV2.sol index d481a293..b9979db4 100644 --- a/src/v2/VaultV2.sol +++ b/src/v2/VaultV2.sol @@ -6,6 +6,7 @@ import { } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "./SemiFungibleVault.sol"; import {IVaultV2} from "./interfaces/IVaultV2.sol"; +import {IVaultFactoryV2} from "./interfaces/IVaultFactoryV2.sol"; import {IWETH} from "./interfaces/IWETH.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { @@ -28,7 +29,6 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { uint256 public immutable strike; // Earthquake bussiness logic bool public immutable isWETH; - address public treasury; address public counterPartyVault; address public factory; address public controller; @@ -55,7 +55,6 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { @param _token address of the token that will be used as collateral; @param _strike uint256 representing the strike price of the vault; @param _controller address of the controller of the vault; - @param _treasury address of the treasury of the vault; */ constructor( bool _isWETH, @@ -65,19 +64,15 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { string memory _tokenURI, address _token, uint256 _strike, - address _controller, - address _treasury + address _controller ) SemiFungibleVault(IERC20(_assetAddress), _name, _symbol, _tokenURI) { if (_controller == address(0)) revert AddressZero(); if (_token == address(0)) revert AddressZero(); if (_assetAddress == address(0)) revert AddressZero(); - if (_treasury == address(0)) revert AddressZero(); token = _token; strike = _strike; factory = msg.sender; controller = _controller; - treasury = _treasury; - whitelistedAddresses[_treasury] = true; isWETH = _isWETH; } @@ -251,22 +246,13 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { /** @notice Factory function, whitelist address - @param _wAddress New treasury address - */ + @param _wAddress whitelist destination address + */ function whiteListAddress(address _wAddress) public onlyFactory { if (_wAddress == address(0)) revert AddressZero(); whitelistedAddresses[_wAddress] = !whitelistedAddresses[_wAddress]; } - /** - @notice Factory function, changes treasury address - @param _treasury New treasury address - */ - function setTreasury(address _treasury) public onlyFactory { - if (_treasury == address(0)) revert AddressZero(); - treasury = _treasury; - } - /** @notice Factory function, changes _counterPartyVault address @param _counterPartyVault New _counterPartyVault address @@ -313,7 +299,7 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { if (_amount > finalTVL[_id]) revert AmountExceedsTVL(); if (epochAccounting[_id] + _amount > finalTVL[_id]) revert AmountExceedsTVL(); - if (!whitelistedAddresses[_receiver] && _receiver != counterPartyVault) + if (!whitelistedAddresses[_receiver] && _receiver != counterPartyVault && _receiver != treasury()) revert DestinationNotAuthorized(_receiver); epochAccounting[_id] += _amount; SemiFungibleVault.asset.safeTransfer(_receiver, _amount); @@ -395,6 +381,10 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { epochCreation = epochConfig[_id].epochCreation; } + function treasury() public returns (address) { + return IVaultFactoryV2(factory).treasury(); + } + function _asset() internal view returns (IERC20) { return asset; } diff --git a/src/v2/interfaces/IVaultFactoryV2.sol b/src/v2/interfaces/IVaultFactoryV2.sol index f30e9370..51879747 100644 --- a/src/v2/interfaces/IVaultFactoryV2.sol +++ b/src/v2/interfaces/IVaultFactoryV2.sol @@ -11,6 +11,8 @@ interface IVaultFactoryV2 { string memory name ) external returns (address); + function treasury() external view returns (address); + function getVaults(uint256) external view returns (address[2] memory); function getEpochFee(uint256) external view returns (uint16); diff --git a/src/v2/interfaces/IVaultV2.sol b/src/v2/interfaces/IVaultV2.sol index 7a5a3f62..531394c5 100644 --- a/src/v2/interfaces/IVaultV2.sol +++ b/src/v2/interfaces/IVaultV2.sol @@ -62,5 +62,4 @@ interface IVaultV2 { view returns (bool); - function setTreasury(address _treasury) external; } diff --git a/src/v2/libraries/CarouselCreator.sol b/src/v2/libraries/CarouselCreator.sol index ead966a3..d88ee259 100644 --- a/src/v2/libraries/CarouselCreator.sol +++ b/src/v2/libraries/CarouselCreator.sol @@ -35,7 +35,6 @@ library CarouselCreator { _marketConfig.token, _marketConfig.strike, _marketConfig.controller, - _marketConfig.treasury, _marketConfig.emissionsToken, _marketConfig.relayerFee, _marketConfig.depositFee, diff --git a/src/v2/libraries/VaultV2Creator.sol b/src/v2/libraries/VaultV2Creator.sol index 0314292c..8aa63346 100644 --- a/src/v2/libraries/VaultV2Creator.sol +++ b/src/v2/libraries/VaultV2Creator.sol @@ -29,8 +29,7 @@ library VaultV2Creator { _marketConfig.tokenURI, _marketConfig.token, _marketConfig.strike, - _marketConfig.controller, - _marketConfig.treasury + _marketConfig.controller ) ); } diff --git a/test/V2/Carousel/CarouselTest.t.sol b/test/V2/Carousel/CarouselTest.t.sol index e6a6427d..2aaaf322 100644 --- a/test/V2/Carousel/CarouselTest.t.sol +++ b/test/V2/Carousel/CarouselTest.t.sol @@ -41,7 +41,6 @@ contract CarouselTest is Helper { TOKEN, STRIKE, controller, - TREASURY, emissionsToken, relayerFee, depositFee, @@ -391,5 +390,9 @@ contract CarouselTest is Helper { vm.stopPrank(); } + // deployer contract acts as factory and must emulate VaultFactoryV2.treasury() + function treasury() public view returns (address) { + return TREASURY; + } } \ No newline at end of file diff --git a/test/V2/FactoryV2Test.t.sol b/test/V2/FactoryV2Test.t.sol index c7939a99..96f4b59d 100644 --- a/test/V2/FactoryV2Test.t.sol +++ b/test/V2/FactoryV2Test.t.sol @@ -264,27 +264,6 @@ contract FactoryV2Test is Helper { assertEq(epochs[1], epochId2); } - - function testChangeTreasuryOnVault() public { - // test revert cases - uint256 marketId = createMarketHelper(); - - vm.expectRevert(VaultFactoryV2.NotTimeLocker.selector); - factory.changeTreasury(uint256(0x2), address(0x20)); - - vm.startPrank(address(factory.timelocker())); - vm.expectRevert(abi.encodeWithSelector(VaultFactoryV2.MarketDoesNotExist.selector, uint256(0x2))); - factory.changeTreasury(uint256(0x2), address(0x20)); - vm.expectRevert(VaultFactoryV2.AddressZero.selector); - factory.changeTreasury(marketId, address(0)); - - // test success case - factory.changeTreasury(marketId, address(0x20)); - address[2] memory vaults = factory.getVaults(marketId); - assertTrue(IVaultV2(vaults[0]).whitelistedAddresses(address(0x20))); - assertTrue(IVaultV2(vaults[1]).whitelistedAddresses(address(0x20))); - vm.stopPrank(); - } function testSetTreasury() public { // test revert cases diff --git a/test/V2/VaultV2Test.t.sol b/test/V2/VaultV2Test.t.sol index 1e5b7d41..e7265f06 100644 --- a/test/V2/VaultV2Test.t.sol +++ b/test/V2/VaultV2Test.t.sol @@ -23,8 +23,7 @@ contract VaultV2Test is Helper { "randomURI", TOKEN, STRIKE, - controller, - TREASURY + controller ); vm.warp(120000); MintableToken(UNDERLYING).mint(address(this)); @@ -37,8 +36,7 @@ contract VaultV2Test is Helper { "randomURI", TOKEN, STRIKE, - controller, - TREASURY + controller ); vault.setCounterPartyVault(address(counterpartyVault)); @@ -58,8 +56,7 @@ contract VaultV2Test is Helper { "randomURI", TOKEN, STRIKE, - controller, - TREASURY + controller ); vm.expectRevert(VaultV2.AddressZero.selector); @@ -71,8 +68,7 @@ contract VaultV2Test is Helper { "randomURI", address(0), // wrong token STRIKE, - controller, - TREASURY + controller ); vm.expectRevert(VaultV2.AddressZero.selector); @@ -84,21 +80,7 @@ contract VaultV2Test is Helper { "randomURI", TOKEN, STRIKE, - address(0), // wrong controller - TREASURY - ); - - vm.expectRevert(VaultV2.AddressZero.selector); - new VaultV2( - false, - UNDERLYING, - "Vault", - "v", - "randomURI", - TOKEN, - STRIKE, - controller, - address(0) // wrong treasury + address(0) // wrong controller ); // test success case @@ -110,8 +92,7 @@ contract VaultV2Test is Helper { "randomURI", TOKEN, STRIKE, - controller, - TREASURY + controller ); assertEq(address(vault2.asset()), UNDERLYING); @@ -120,7 +101,6 @@ contract VaultV2Test is Helper { assertEq(vault2.token(), TOKEN); assertEq(vault2.strike(), STRIKE); assertEq(vault2.controller(), controller); - assertTrue(vault2.whitelistedAddresses(TREASURY)); assertEq(vault2.factory(), address(this)); } @@ -540,4 +520,9 @@ contract VaultV2Test is Helper { vault.setEpoch(_epochBegin, _epochEnd, _epochId); counterpartyVault.setEpoch(_epochBegin, _epochEnd, _epochId); } + + // deployer contract acts as factory and must emulate VaultFactoryV2.treasury() + function treasury() public view returns (address) { + return TREASURY; + } } From e5608978c48f84a9c0928cb5774436bdb8abfe99 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 10 Apr 2023 19:19:55 +0200 Subject: [PATCH 14/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/181 --- src/v2/TimeLock.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v2/TimeLock.sol b/src/v2/TimeLock.sol index c882d0d8..8a0eb4d1 100644 --- a/src/v2/TimeLock.sol +++ b/src/v2/TimeLock.sol @@ -10,7 +10,7 @@ contract TimeLock { address public policy; - uint32 public constant MIN_DELAY = 3 days; + uint32 public constant MIN_DELAY = 7 days; uint32 public constant MAX_DELAY = 30 days; uint32 public constant GRACE_PERIOD = 14 days; From f0aee47ac5c9cf9467de5a910cb59c5399100a44 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 10 Apr 2023 20:59:37 +0200 Subject: [PATCH 15/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/122 --- src/v2/Carousel/Carousel.sol | 25 ++++++++++++++++++++++--- src/v2/VaultV2.sol | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index d968c05f..ecf000be 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -571,16 +571,35 @@ contract Carousel is VaultV2 { ADMIN FUNCTIONS //////////////////////////////////////////////////////////////*/ + /** + @notice This function is called by the controller if the epoch has started, but the counterparty vault has no value. In this case the users can withdraw their deposit. Additionally, emissions are transferred to the treasury. + @param _id uint256 identifier of the epoch + */ + function setEpochNull(uint256 _id) + public + override + onlyController + epochIdExists(_id) + epochHasEnded(_id) + { + epochNull[_id] = true; + if(emissions[_id] > 0) { + emissionsToken.safeTransfer(treasury(), emissions[_id]); + emissions[_id] = 0; + } + } + + /** @notice sets emissions * @param _epochId epoch id - * @param _emissionsRate emissions rate + * @param _emissionAmount emissions rate */ - function setEmissions(uint256 _epochId, uint256 _emissionsRate) + function setEmissions(uint256 _epochId, uint256 _emissionAmount) external onlyFactory epochIdExists(_epochId) { - emissions[_epochId] = _emissionsRate; + emissions[_epochId] = _emissionAmount; } /** @notice changes relayer fee diff --git a/src/v2/VaultV2.sol b/src/v2/VaultV2.sol index b9979db4..098365b9 100644 --- a/src/v2/VaultV2.sol +++ b/src/v2/VaultV2.sol @@ -325,6 +325,7 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { */ function setEpochNull(uint256 _id) public + virtual onlyController epochIdExists(_id) epochHasEnded(_id) From acf4ce4c9106d804b060c5949c8c031918d3a556 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Tue, 11 Apr 2023 13:16:55 +0200 Subject: [PATCH 16/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/108 --- src/v2/Controllers/ControllerPeggedAssetV2.sol | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/v2/Controllers/ControllerPeggedAssetV2.sol b/src/v2/Controllers/ControllerPeggedAssetV2.sol index 0587c869..32ffbae0 100644 --- a/src/v2/Controllers/ControllerPeggedAssetV2.sol +++ b/src/v2/Controllers/ControllerPeggedAssetV2.sol @@ -155,6 +155,13 @@ contract ControllerPeggedAssetV2 { collateralVault.epochExists(_epochId) == false ) revert EpochNotExist(); + if ( + premiumVault.totalAssets(_epochId) == 0 || + collateralVault.totalAssets(_epochId) == 0 + ) { + revert VaultZeroTVL(); + } + (, uint40 epochEnd, ) = premiumVault.getEpochConfig(_epochId); if (block.timestamp <= uint256(epochEnd)) revert EpochNotExpired(); From 2f51468aa4cd97876ba3f748de1c86f8bc974b12 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Tue, 11 Apr 2023 13:57:32 +0200 Subject: [PATCH 17/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/70 --- .../Controllers/ControllerPeggedAssetV2.sol | 10 ++++-- .../ControllerPeggedAssetV2Test.t.sol | 32 +++++++++++++++++-- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/v2/Controllers/ControllerPeggedAssetV2.sol b/src/v2/Controllers/ControllerPeggedAssetV2.sol index 32ffbae0..98a58fc6 100644 --- a/src/v2/Controllers/ControllerPeggedAssetV2.sol +++ b/src/v2/Controllers/ControllerPeggedAssetV2.sol @@ -14,6 +14,7 @@ contract ControllerPeggedAssetV2 { IVaultFactoryV2 public immutable vaultFactory; AggregatorV2V3Interface internal sequencerUptimeFeed; + uint256 private constant MAX_UPDATE_TRESHOLD = 2 days; uint16 private constant GRACE_PERIOD_TIME = 3600; address public immutable treasury; @@ -282,7 +283,8 @@ contract ControllerPeggedAssetV2 { , /*uint80 roundId*/ int256 answer, - uint256 startedAt, /*uint256 updatedAt*/ /*uint80 answeredInRound*/ + uint256 startedAt, + /*uint256 updatedAt*/ /*uint80 answeredInRound*/ , ) = sequencerUptimeFeed.latestRoundData(); @@ -303,8 +305,11 @@ contract ControllerPeggedAssetV2 { AggregatorV3Interface priceFeed = AggregatorV3Interface( vaultFactory.tokenToOracle(_token) ); - (uint80 roundID, int256 price, , , uint80 answeredInRound) = priceFeed + (uint80 roundID, int256 price, ,uint256 updatedAt, uint80 answeredInRound) = priceFeed .latestRoundData(); + + if (updatedAt < block.timestamp - MAX_UPDATE_TRESHOLD) revert PriceOutdated(); + uint256 decimals = priceFeed.decimals(); if (decimals < 18) { @@ -362,6 +367,7 @@ contract ControllerPeggedAssetV2 { error EpochNotExpired(); error VaultNotZeroTVL(); error VaultZeroTVL(); + error PriceOutdated(); /*////////////////////////////////////////////////////////////// EVENTS diff --git a/test/V2/Controllers/ControllerPeggedAssetV2Test.t.sol b/test/V2/Controllers/ControllerPeggedAssetV2Test.t.sol index 15e31b20..6fc2d348 100644 --- a/test/V2/Controllers/ControllerPeggedAssetV2Test.t.sol +++ b/test/V2/Controllers/ControllerPeggedAssetV2Test.t.sol @@ -10,6 +10,7 @@ import "../../../src/v2/VaultFactoryV2.sol"; import "../../../src/v2/TimeLock.sol"; contract ControllerPeggedAssetV2Test is Helper { + using stdStorage for StdStorage; VaultV2 vault; VaultV2 counterpartyVault; ControllerPeggedAssetV2 controller; @@ -37,7 +38,7 @@ contract ControllerPeggedAssetV2Test is Helper { controller = new ControllerPeggedAssetV2( address(factory), - address(0x1), + address(new Sequencer()), TREASURY ); @@ -71,8 +72,8 @@ contract ControllerPeggedAssetV2Test is Helper { ) ); - begin = uint40(block.timestamp); - end = uint40(block.timestamp + 1 days); + begin = uint40(block.timestamp+ 30 days); + end = uint40(block.timestamp + 35 days); withdrawalFee = 10; (epochId, ) = factory.createEpoch( @@ -89,6 +90,16 @@ contract ControllerPeggedAssetV2Test is Helper { function testTriggerDepeg() public { // TODO // revert cases + stdstore + .target(address(factory)) + .sig("tokenToOracle(address)") + .with_key(TOKEN) + .checked_write(address(this)); // set oracle with faulty updated at time + + vm.warp(begin + 1); + + vm.expectRevert(ControllerPeggedAssetV2.PriceOutdated.selector); + controller.triggerDepeg(marketId, epochId); // success case } @@ -108,4 +119,19 @@ contract ControllerPeggedAssetV2Test is Helper { // success case } + function latestRoundData() public view returns (uint80, int256, uint256, uint256, uint80) { + return (100, int256(STRIKE) - int256(1), 0, block.timestamp - 3 days, 100); + } + + function decimals() public view returns (uint8) { + return 18; + } + +} + + +contract Sequencer is Helper { + function latestRoundData() public view returns (uint80, int256, uint256, uint256, uint80) { + return (100, 0, block.timestamp - 1 days, block.timestamp, 100); + } } \ No newline at end of file From a2f139eb9fc280cb6778aa5038100878f6213fbe Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Tue, 11 Apr 2023 14:13:45 +0200 Subject: [PATCH 18/31] fix https://github.com/sherlock-audit/2023-03-Y2K-judging/issues/1 --- src/v2/Carousel/Carousel.sol | 4 ++-- src/v2/Carousel/CarouselFactory.sol | 14 ++++++++++---- src/v2/interfaces/ICarousel.sol | 8 ++++---- test/V2/Carousel/CarouselTest.t.sol | 6 +++--- test/V2/e2e/EndToEndCarouselTest.t.sol | 12 ++++++------ 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index ecf000be..8991157c 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -733,14 +733,14 @@ contract Carousel is VaultV2 { /** @notice returns the deposit queue length * @return queue length for the deposit */ - function getDepositQueueLenght() public view returns (uint256) { + function getDepositQueueLength() public view returns (uint256) { return depositQueue.length; } /** @notice returns the queue length for the rollover * @return queue length for the rollover */ - function getRolloverQueueLenght() public view returns (uint256) { + function getRolloverQueueLength() public view returns (uint256) { return rolloverQueue.length; } diff --git a/src/v2/Carousel/CarouselFactory.sol b/src/v2/Carousel/CarouselFactory.sol index 492d05bd..52d8a113 100644 --- a/src/v2/Carousel/CarouselFactory.sol +++ b/src/v2/Carousel/CarouselFactory.sol @@ -194,10 +194,15 @@ contract CarouselFactory is VaultFactoryV2 { address[2] memory vaults = marketIdToVaults[_marketIndex]; if (vaults[0] == address(0)) revert MarketDoesNotExist(_marketIndex); - ICarousel insr = ICarousel(vaults[0]); - ICarousel risk = ICarousel(vaults[1]); - insr.changeRelayerFee(_relayerFee); - risk.changeRelayerFee(_relayerFee); + + ICarousel premium = ICarousel(vaults[0]); + ICarousel collat = ICarousel(vaults[1]); + + if(premium.getDepositQueueLength() > 0) revert QueueNotEmpty(); + if(collat.getDepositQueueLength() > 0) revert QueueNotEmpty(); + + premium.changeRelayerFee(_relayerFee); + collat.changeRelayerFee(_relayerFee); emit ChangedRelayerFee(_relayerFee, _marketIndex); } @@ -257,6 +262,7 @@ contract CarouselFactory is VaultFactoryV2 { error InvalidRelayerFee(); error InvalidVaultIndex(); error InvalidDepositFee(); + error QueueNotEmpty(); /*////////////////////////////////////////////////////////////// EVENTS diff --git a/src/v2/interfaces/ICarousel.sol b/src/v2/interfaces/ICarousel.sol index d81edf36..3d35d7ef 100644 --- a/src/v2/interfaces/ICarousel.sol +++ b/src/v2/interfaces/ICarousel.sol @@ -82,10 +82,6 @@ interface ICarousel { view returns (uint256); - function getDepositQueueLenght() external view; - - function getRolloverQueueLenght() external view; - function emissionsToken() external view returns (address); function relayerFee() external view returns (uint256); @@ -95,4 +91,8 @@ interface ICarousel { function emissions(uint256 _epochId) external view returns (uint256); function cleanupRolloverQueue(address[] memory) external; + + function getDepositQueueLength() external view returns (uint256); + + function getRolloverQueueLength() external view returns (uint256); } diff --git a/test/V2/Carousel/CarouselTest.t.sol b/test/V2/Carousel/CarouselTest.t.sol index 2aaaf322..6b744fcc 100644 --- a/test/V2/Carousel/CarouselTest.t.sol +++ b/test/V2/Carousel/CarouselTest.t.sol @@ -75,7 +75,7 @@ contract CarouselTest is Helper { vm.stopPrank(); uint256 _queueLength = 1; - assertEq(vault.getDepositQueueLenght(), _queueLength); + assertEq(vault.getDepositQueueLength(), _queueLength); // test revert cases // should revert if epochId is 0 as this epoch is not supposed to minted ever vm.expectRevert(Carousel.InvalidEpochId.selector); @@ -136,7 +136,7 @@ contract CarouselTest is Helper { _queueLength = 3; - assertEq(vault.getDepositQueueLenght(), _queueLength); + assertEq(vault.getDepositQueueLength(), _queueLength); // should only do as many operations as queue length // please check logs: test forge test -m testDepositInQueue -vvvv vault.mintDepositInQueue(_epochId, 230000); @@ -228,7 +228,7 @@ contract CarouselTest is Helper { helperDepositInEpochs(_epochId,USER5, true); helperDepositInEpochs(_epochId,USER6, true); - assertEq(vault.getDepositQueueLenght(), 6); + assertEq(vault.getDepositQueueLength(), 6); // check balance of relayer uint256 balanceBefore = IERC20(UNDERLYING).balanceOf(address(this)); diff --git a/test/V2/e2e/EndToEndCarouselTest.t.sol b/test/V2/e2e/EndToEndCarouselTest.t.sol index 75b719c2..28dc672a 100644 --- a/test/V2/e2e/EndToEndCarouselTest.t.sol +++ b/test/V2/e2e/EndToEndCarouselTest.t.sol @@ -162,8 +162,8 @@ contract EndToEndCarouselTest is Helper { //assert queue length collateralQueueLength = 2; premiumQueueLength = 1; - assertEq(Carousel(collateral).getDepositQueueLenght(), collateralQueueLength); - assertEq(Carousel(premium).getDepositQueueLenght(), premiumQueueLength); + assertEq(Carousel(collateral).getDepositQueueLength(), collateralQueueLength); + assertEq(Carousel(premium).getDepositQueueLength(), premiumQueueLength); //mint deposit in queue Carousel(collateral).mintDepositInQueue(epochId, collateralQueueLength); @@ -257,7 +257,7 @@ contract EndToEndCarouselTest is Helper { vm.startPrank(USER); //delist rollover - uint256 beforeQueueLength = Carousel(collateral).getRolloverQueueLenght(); + uint256 beforeQueueLength = Carousel(collateral).getRolloverQueueLength(); Carousel(collateral).delistInRollover(USER); //assert delisted rollover position in queue assets are 0 @@ -280,12 +280,12 @@ contract EndToEndCarouselTest is Helper { // cleanup queue from delisted users vm.startPrank(address(factory)); - uint256 beforeQueueLength2 = Carousel(collateral).getRolloverQueueLenght(); + uint256 beforeQueueLength2 = Carousel(collateral).getRolloverQueueLength(); assertEq(beforeQueueLength2, 2); address[] memory addressesToDelist = new address[](1); addressesToDelist[0] = USER; Carousel(collateral).cleanUpRolloverQueue(addressesToDelist); - uint256 afterQueueLength2 = Carousel(collateral).getRolloverQueueLenght(); + uint256 afterQueueLength2 = Carousel(collateral).getRolloverQueueLength(); assertEq(afterQueueLength2, 1); vm.stopPrank(); @@ -296,7 +296,7 @@ contract EndToEndCarouselTest is Helper { assertTrue(Carousel(collateral).getRolloverIndex(USER2) == 0); //delist rollover - beforeQueueLength = Carousel(collateral).getRolloverQueueLenght(); + beforeQueueLength = Carousel(collateral).getRolloverQueueLength(); Carousel(collateral).delistInRollover(USER2); //assert balance in next epoch From 5b5cd83332a488cfd03a8f2b347ea33840dc3fce Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 17 Apr 2023 00:42:39 +0200 Subject: [PATCH 19/31] change oracle for token --- script/v2/Helper.sol | 182 ++++++++++ script/v2/V2DeploymentScript.s.sol | 190 +++++++++- src/v2/Carousel/Carousel.sol | 110 +----- src/v2/Carousel/CarouselFactory.sol | 20 ++ .../Controllers/ControllerPeggedAssetV2.sol | 6 +- test/V2/Carousel/CarouselTest.t.sol | 21 +- test/V2/FactoryV2Test.t.sol | 326 ++++++++++++++++++ test/V2/e2e/EndToEndCarouselTest.t.sol | 4 - 8 files changed, 728 insertions(+), 131 deletions(-) create mode 100644 script/v2/Helper.sol diff --git a/script/v2/Helper.sol b/script/v2/Helper.sol new file mode 100644 index 00000000..6297c70d --- /dev/null +++ b/script/v2/Helper.sol @@ -0,0 +1,182 @@ +// SPDX-License-Identifier; +pragma solidity 0.8.17; + +import "forge-std/Script.sol"; +import "forge-std/StdJson.sol"; +import "forge-std/Test.sol"; +//TODO change this after deploy y2k token +import "@openzeppelin/contracts/utils/Strings.sol"; +// import "../keepers/KeeperDepeg.sol"; +// import "../keepers/KeeperEndEpoch.sol"; + +/// @author MiguelBits + +contract HelperV2 is Script { + using stdJson for string; + + struct ConfigVariables{ + uint256 amountOfNewEpochs; + uint256 amountOfNewFarms; + uint256 amountOfNewMarkets; + uint256[] epochsIds; + uint256[] farmsIds; + uint256[] marketsIds; + bool newEpochs; + bool newFarms; + bool newMarkets; + } + struct ConfigAddresses { + address admin; + address arbitrum_sequencer; + address controller; + address gelatoOpsV2; + address gelatoTaskTreasury; + address keeperDepeg; + address keeperEndEpoch; + address oracleDAI; + address oracleFEI; + address oracleFRAX; + address oracleMIM; + address oracleUSDC; + address oracleUSDT; + address policy; + address rewardsFactory; + address tokenDAI; + address tokenFEI; + address tokenFRAX; + address tokenMIM; + address tokenUSDC; + address tokenUSDT; + address treasury; + address vaultFactory; + address weth; + address y2k; + } + + struct ConfigMarket { + uint256 marketId; + string name; + address oracle; + int256 strikePrice; + address token; + } + + struct ConfigEpochs { + uint256 epochBegin; + uint256 epochEnd; + uint256 epochFee; + uint256 marketId; + } + + struct ConfigFarms { + uint256 epochEnd; + string farmRewardsHEDGE; + string farmRewardsRISK; + uint marketId; + } + + + + ConfigVariables configVariables; + + function setVariables() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/configJSON.json"); + string memory json = vm.readFile(path); + bytes memory parseJsonByteCode = json.parseRaw(".variables"); + configVariables = abi.decode(parseJsonByteCode, (ConfigVariables)); + // console2.log("ConfigVariables ", rawConstants.amountOfNewMarkets); + } + + // function contractToAddresses(ConfigAddresses memory configAddresses) public { + // vaultFactory = VaultFactory(configAddresses.vaultFactory); + // controller = Controller(configAddresses.controller); + // rewardsFactory = RewardsFactory(configAddresses.rewardsFactory); + // y2k = Y2K(configAddresses.y2k); + // keeperDepeg = KeeperGelatoDepeg(configAddresses.keeperDepeg); + // keeperEndEpoch = KeeperGelatoEndEpoch(configAddresses.keeperEndEpoch); + // } + + // function startKeepers(uint _marketIndex, uint _epochEnd) public { + // keeperDepeg.startTask(_marketIndex, _epochEnd); + // keeperEndEpoch.startTask(_marketIndex, _epochEnd); + // } + + function getConfigAddresses(bool isTestEnv) public returns (ConfigAddresses memory) { + string memory root = vm.projectRoot(); + string memory path; + if(isTestEnv){ + path = string.concat(root, "/configTestEnv.json"); + } + else{ + path = string.concat(root, "/configAddresses.json"); + } + string memory json = vm.readFile(path); + bytes memory parseJsonByteCode = json.parseRaw(".configAddresses[0]"); + ConfigAddresses memory rawConstants = abi.decode(parseJsonByteCode, (ConfigAddresses)); + //console2.log("ConfigAddresses ", rawConstants.weth); + return rawConstants; + } + + function getConfigMarket(uint256 index) public returns (ConfigMarket memory) { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/configJSON.json"); + string memory json = vm.readFile(path); + string memory indexString = string.concat(".markets", "[", Strings.toString(index), "]"); + bytes memory transactionDetails = json.parseRaw(indexString); + ConfigMarket memory rawConstants = abi.decode(transactionDetails, (ConfigMarket)); + //console2.log("ConfigMarkets ", rawConstants.name); + return rawConstants; + } + + function getConfigEpochs(uint256 index) public returns (ConfigEpochs memory) { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/configJSON.json"); + string memory json = vm.readFile(path); + string memory indexString = string.concat(".epochs", "[", Strings.toString(index), "]"); + bytes memory transactionDetails = json.parseRaw(indexString); + ConfigEpochs memory rawConstants = abi.decode(transactionDetails, (ConfigEpochs)); + //console2.log("ConfigEpochs ", rawConstants.name); + return rawConstants; + } + + function getConfigFarms(uint256 index) public returns (ConfigFarms memory) { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/configJSON.json"); + string memory json = vm.readFile(path); + string memory indexString = string.concat(".farms", "[", Strings.toString(index), "]"); + bytes memory transactionDetails = json.parseRaw(indexString); + ConfigFarms memory rawConstants = abi.decode(transactionDetails, (ConfigFarms)); + //console2.log("ConfigEpochs ", rawConstants.name); + return rawConstants; + } + + function verifyConfig(ConfigMarket memory marketConstants) public view { + // require(marketConstants.epochBegin < marketConstants.epochEnd, "epochBegin is not < epochEnd"); + // require(marketConstants.epochEnd > block.timestamp, "epochEnd in the past"); + // require(marketConstants.strikePrice > 900000000000000000, "strikePrice is not above 0.90"); + // require(marketConstants.strikePrice < 1000000000000000000, "strikePrice is not below 1.00"); + // //TODO add more checks + } + + function verifyConfig(ConfigMarket memory marketConstants, ConfigEpochs memory epochConstants) public view { + // require(epochConstants.epochBegin > marketConstants.epochEnd, "epochBegin is not > marketEnd"); + // require(epochConstants.epochBegin < epochConstants.epochEnd, "epochBegin is not < epochEnd"); + // require(epochConstants.epochEnd > block.timestamp, "epochEnd in the past"); + // //TODO add more checks + + } + + function stringToUint(string memory s) public pure returns (uint) { + bytes memory b = bytes(s); + uint result = 0; + for (uint256 i = 0; i < b.length; i++) { + uint256 c = uint256(uint8(b[i])); + if (c >= 48 && c <= 57) { + result = result * 10 + (c - 48); + } + } + return result; + } + +} \ No newline at end of file diff --git a/script/v2/V2DeploymentScript.s.sol b/script/v2/V2DeploymentScript.s.sol index aeb81664..f1342c83 100644 --- a/script/v2/V2DeploymentScript.s.sol +++ b/script/v2/V2DeploymentScript.s.sol @@ -5,24 +5,35 @@ pragma solidity ^0.8.17; import "forge-std/Script.sol"; import "forge-std/StdJson.sol"; import "forge-std/Test.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../../src/v2/VaultFactoryV2.sol"; import "../../src/v2/Carousel/CarouselFactory.sol"; +import "../../src/v2/Controllers/ControllerPeggedAssetV2.sol"; import "../../src/v2/TimeLock.sol"; +import "./Helper.sol"; + + + //forge script V2DeploymentScript --rpc-url $ARBITRUM_RPC_URL --broadcast --verify -slow -vv // forge verify-contract --chain-id 42161 --num-of-optimizations 1000000 --watch --constructor-args $(cast abi-encode "constructor(address,address,address,address,uint256)" 0xaC0D2cF77a8F8869069fc45821483701A264933B 0xaC0D2cF77a8F8869069fc45821483701A264933B 0x65c936f008BC34fE819bce9Fa5afD9dc2d49977f 0x447deddf312ad609e2f85fd23130acd6ba48e8b7 1668384000) --compiler-version v0.8.15+commit.e14f2714 0x69b614f03554c7e0da34645c65852cc55400d0f9 src/rewards/StakingRewards.sol:StakingRewards $arbiscanApiKey // forge script script/v2/V2DeploymentScript.s.sol --rpc-url $ARBITRUM_RPC_URL --private-key $PRIVATE_KEY --broadcast --verify --skip-simulation --slow -vvvv -contract V2DeploymentScript is Script { +contract V2DeploymentScript is Script, HelperV2 { using stdJson for string; - function run() public { - + address policy = 0xCCA23C05a9Cf7e78830F3fd55b1e8CfCCbc5E50F; + address weth = 0x6BE37a65E46048B1D12C0E08d9722402A5247Ff1; + address treasury = 0xCCA23C05a9Cf7e78830F3fd55b1e8CfCCbc5E50F; + address emissionToken = 0x5D59e5837F7e5d0F710178Eda34d9eCF069B36D2; - // ConfigAddresses memory addresses = getConfigAddresses(false); + address controller; + function run() public { + + ConfigAddresses memory addresses = getConfigAddresses(false); // console2.log("Address admin", addresses.admin); // console2.log("Address arbitrum_sequencer", addresses.arbitrum_sequencer); // console2.log("Address oracleDAI", addresses.oracleDAI); @@ -49,27 +60,40 @@ contract V2DeploymentScript is Script { vm.startBroadcast(privateKey); console2.log("Broadcast sender", msg.sender); + + + policy = msg.sender; + treasury = msg.sender; - address policy = 0xaC0D2cF77a8F8869069fc45821483701A264933B; - address weth = 0xaC0D2cF77a8F8869069fc45821483701A264933B; - address treasury = 0x65c936f008BC34fE819bce9Fa5afD9dc2d49977f; - address emissionToken = 0xaC0D2cF77a8F8869069fc45821483701A264933B; - address timeLock = address(new TimeLock(policy)); + // address timeLock = address(new TimeLock(policy)); - // CarouselFactory vaultFactory = new CarouselFactory(policy, weth, treasury, emissionToken); + // CarouselFactory vaultFactory = new CarouselFactory(weth, treasury, policy, emissionToken); - VaultFactoryV2 vaultFactory = new VaultFactoryV2(weth, treasury, timeLock); + // VaultFactoryV2 vaultFactory = new VaultFactoryV2(weth, treasury, timeLock); // console2.log("Broadcast admin ", addresses.admin); // console2.log("Broadcast policy", addresses.policy); //start setUp(); // vaultFactory = new VaultFactory(addresses.treasury, addresses.weth, addresses.policy); - // controller = new Controller(address(vaultFactory), addresses.arbitrum_sequencer); + // controller = address(new ControllerPeggedAssetV2(address(vaultFactory), addresses.arbitrum_sequencer, treasury)); + + // vaultFactory.whitelistController(address(controller)); + + + // deployMarketsV2(address(vaultFactory)); - // vaultFactory.setController(address(controller)); + // IERC20(emissionToken).approve(0x1A5151C53bb041A7f70B40adfAEFe0FDfE05b2d8, 200 ether); + CarouselFactory(0x1A5151C53bb041A7f70B40adfAEFe0FDfE05b2d8).createEpochWithEmissions( + uint256(79901062978974686921194727646590599359178698799258240092258231289348051120802), + 1681494640, + 1681581040, + 50, + 0, + 0 + ); //stop setUp(); @@ -86,4 +110,144 @@ contract V2DeploymentScript is Script { vm.stopBroadcast(); } + + function deployMarketsV2( address factory) public { + + ConfigAddresses memory addresses = getConfigAddresses(false); + + + IERC20(emissionToken).approve(address(factory), 200 ether); + + ( address prem, address collat, uint256 marketId) = CarouselFactory(factory).createNewCarouselMarket( + CarouselFactory.CarouselMarketConfigurationCalldata( + addresses.tokenUSDC, + 1 ether - 1, + addresses.oracleUSDC, + weth, + "y2kUSDC_999*", + "https://y2k.finance", + address(controller), + 1 gwei, + 10, + 1 ether + ) + ); + + CarouselFactory(factory).createEpochWithEmissions( + marketId, + 1683891705, + 1689162105, + 50, + 1 ether, + 10 ether + ); + + // CarouselFactory(factory).createEpochWithEmissions( + // marketId, + // 1689419676, + // 1689506076, + // 50, + // 1 ether, + // 10 ether + // ); + + // CarouselFactory(factory).createEpochWithEmissions( + // marketId, + // 1689592476, + // 1689678876, + // 50, + // 1 ether, + // 10 ether + // ); + + ( prem, collat, marketId) = CarouselFactory(factory).createNewCarouselMarket( + CarouselFactory.CarouselMarketConfigurationCalldata( + addresses.tokenUSDT, + 1 ether - 1, + addresses.oracleUSDT, + weth, + "y2kUSDT_999*", + "https://y2k.finance", + address(controller), + 1 gwei, + 10, + 1 ether + ) + ); + + // CarouselFactory(factory).createEpochWithEmissions( + // marketId, + // 1683891705, + // 1689162105, + // 50, + // 1 ether, + // 10 ether + // ); + + CarouselFactory(factory).createEpochWithEmissions( + marketId, + 1689419676, + 1689506076, + 50, + 1 ether, + 10 ether + ); + + // CarouselFactory(factory).createEpochWithEmissions( + // marketId, + // 1689592476, + // 1689678876, + // 50, + // 1 ether, + // 10 ether + // ); + + ( prem, collat, marketId) = CarouselFactory(factory).createNewCarouselMarket( + CarouselFactory.CarouselMarketConfigurationCalldata( + addresses.tokenDAI, + 1 ether - 1, + addresses.oracleDAI, + weth, + "y2kDAI_999*", + "https://y2k.finance", + address(controller), + 1 gwei, + 10, + 1 ether + ) + ); + + // CarouselFactory(factory).createEpochWithEmissions( + // marketId, + // 1683891705, + // 1689162105, + // 50, + // 1 ether, + // 10 ether + // ); + + // CarouselFactory(factory).createEpochWithEmissions( + // marketId, + // 1689419676, + // 1689506076, + // 50, + // 1 ether, + // 10 ether + // ); + + CarouselFactory(factory).createEpochWithEmissions( + marketId, + 1689592476, + 1689678876, + 50, + 1 ether, + 10 ether + ); + + + } + + function deployEpoch( address factory) public { + + } } \ No newline at end of file diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index 8991157c..e1c27d0f 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -27,7 +27,6 @@ contract Carousel is VaultV2 { QueueItem[] public rolloverQueue; QueueItem[] public depositQueue; mapping(uint256 => uint256) public rolloverAccounting; - mapping(uint256 => mapping(address => uint256)) public _emissionsBalances; mapping(uint256 => uint256) public emissions; /*////////////////////////////////////////////////////////////// @@ -154,7 +153,6 @@ contract Carousel is VaultV2 { ) revert OwnerDidNotAuthorize(msg.sender, _owner); _burn(_owner, _id, _assets); - _burnEmissions(_owner, _id, _assets); uint256 entitledShares; uint256 entitledEmissions = previewEmissionsWithdraw(_id, _assets); if (epochNull[_id] == false) { @@ -169,13 +167,14 @@ contract Carousel is VaultV2 { emissionsToken.safeTransfer(_receiver, entitledEmissions); } - emit Withdraw( + emit WithdrawWithEmissions( msg.sender, _receiver, _owner, _id, _assets, - entitledShares + entitledShares, + entitledEmissions ); return entitledShares; @@ -201,17 +200,6 @@ contract Carousel is VaultV2 { "ERC1155: caller is not owner nor approved" ); _safeTransferFrom(from, to, id, amount, data); - // emissions transfer - uint256 fromBalance = _emissionsBalances[id][from]; - require( - fromBalance >= amount, - "ERC1155: insufficient balance for transfer" - ); - unchecked { - _emissionsBalances[id][from] = fromBalance - amount; - } - _emissionsBalances[id][to] += amount; - emit TransferSingleEmissions(_msgSender(), from, to, id, amount); } /** @@ -426,12 +414,6 @@ contract Carousel is VaultV2 { queue[index].epochId, originalDepositValue ); - // transfer emission tokens out of contract otherwise user could not access them as vault shares are burned - _burnEmissions( - queue[index].receiver, - queue[index].epochId, - originalDepositValue - ); // @note emission token is a known token which has no before transfer hooks which makes transfer safer emissionsToken.safeTransfer( queue[index].receiver, @@ -441,13 +423,17 @@ contract Carousel is VaultV2 { ) ); - emit Withdraw( + emit WithdrawWithEmissions( msg.sender, queue[index].receiver, queue[index].receiver, _epochId, originalDepositValue, - entitledAmount + entitledAmount, + previewEmissionsWithdraw( + queue[index].epochId, + originalDepositValue + ) ); uint256 assetsToMint = queue[index].assets - relayerFeeInShares; _mintShares(queue[index].receiver, _epochId, assetsToMint); @@ -521,51 +507,8 @@ contract Carousel is VaultV2 { uint256 amount ) internal { _mint(to, id, amount, EMPTY); - _mintEmissions(to, id, amount); } - /** @notice mints emission shares based of vault shares for user - @param to address of receiver - @param id epoch id - @param amount amount of shares to mint - */ - function _mintEmissions( - address to, - uint256 id, - uint256 amount - ) internal { - require(to != address(0), "ERC1155: mint to the zero address"); - - _emissionsBalances[id][to] += amount; - emit TransferSingleEmissions(_msgSender(), address(0), to, id, amount); - } - - /** @notice burns emission shares of vault for user - @param from address of sender - @param id epoch id - @param amount amount of shares to burn - */ - function _burnEmissions( - address from, - uint256 id, - uint256 amount - ) internal { - require(from != address(0), "ERC1155: burn from the zero address"); - - uint256 fromBalance = _emissionsBalances[id][from]; - require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); - unchecked { - _emissionsBalances[id][from] = fromBalance - amount; - } - - emit TransferSingleEmissions( - _msgSender(), - from, - address(0), - id, - amount - ); - } /*/////////////////////////////////////////////////////////////// ADMIN FUNCTIONS @@ -822,17 +765,6 @@ contract Carousel is VaultV2 { } } - /** @notice returns the total emissions balance - * @return totalEmissions total emissions balance - */ - function balanceOfEmissions(address _owner, uint256 _id) - public - view - returns (uint256) - { - return _emissionsBalances[_id][_owner]; - } - /*////////////////////////////////////////////////////////////// STRUCTS //////////////////////////////////////////////////////////////*/ @@ -906,6 +838,16 @@ contract Carousel is VaultV2 { EVENTS //////////////////////////////////////////////////////////////*/ + event WithdrawWithEmissions( + address caller, + address receiver, + address indexed owner, + uint256 indexed id, + uint256 assets, + uint256 shares, + uint256 emissions + ); + /** @notice emitted when a deposit is queued * @param sender the address of the sender * @param receiver the address of the receiver @@ -936,18 +878,4 @@ contract Carousel is VaultV2 { uint256 epochId ); - /** @notice emitted when emissions are transfered - * @param operator the address of the operator - * @param from the address of the sender - * @param to the address of the receiver - * @param id the id of the emissions - * @param value the amount of emissions - */ - event TransferSingleEmissions( - address indexed operator, - address indexed from, - address indexed to, - uint256 id, - uint256 value - ); } diff --git a/src/v2/Carousel/CarouselFactory.sol b/src/v2/Carousel/CarouselFactory.sol index 52d8a113..ce62560f 100644 --- a/src/v2/Carousel/CarouselFactory.sol +++ b/src/v2/Carousel/CarouselFactory.sol @@ -165,6 +165,16 @@ contract CarouselFactory is VaultFactoryV2 { emissionsToken.safeTransferFrom(treasury, vaults[1], _collatEmissions); ICarousel(vaults[1]).setEmissions(epochId, _collatEmissions); + + emit EpochCreatedWithEmissions( + epochId, + _marketId, + _epochBegin, + _epochEnd, + _withdrawalFee, + _permiumEmissions, + _collatEmissions + ); } // to prevent the creation of epochs without emissions @@ -276,4 +286,14 @@ contract CarouselFactory is VaultFactoryV2 { ); event ChangedRelayerFee(uint256 relayerFee, uint256 marketIndex); + + event EpochCreatedWithEmissions( + uint256 epochId, + uint256 marketId, + uint40 epochBegin, + uint40 epochEnd, + uint16 withdrawalFee, + uint256 premiumEmissions, + uint256 collateralEmissions + ); } diff --git a/src/v2/Controllers/ControllerPeggedAssetV2.sol b/src/v2/Controllers/ControllerPeggedAssetV2.sol index 98a58fc6..2e132ae7 100644 --- a/src/v2/Controllers/ControllerPeggedAssetV2.sol +++ b/src/v2/Controllers/ControllerPeggedAssetV2.sol @@ -134,7 +134,7 @@ contract ControllerPeggedAssetV2 { ), true, block.timestamp, - price + uint256(price) ); } @@ -379,7 +379,7 @@ contract ControllerPeggedAssetV2 { * @param tvl TVL * @param strikeMet Flag if event isDisaster * @param time time - * @param depegPrice Price that triggered depeg + * @param strikeData Data that triggered depeg */ event EpochResolved( uint256 indexed epochId, @@ -387,7 +387,7 @@ contract ControllerPeggedAssetV2 { VaultTVL tvl, bool strikeMet, uint256 time, - int256 depegPrice + uint256 strikeData ); /** @notice Sets epoch to null when event is emitted diff --git a/test/V2/Carousel/CarouselTest.t.sol b/test/V2/Carousel/CarouselTest.t.sol index 6b744fcc..9c087440 100644 --- a/test/V2/Carousel/CarouselTest.t.sol +++ b/test/V2/Carousel/CarouselTest.t.sol @@ -100,7 +100,6 @@ contract CarouselTest is Helper { vm.stopPrank(); // test user balances assertEq(vault.balanceOf(USER, _epochId), 10 ether - relayerFee); - assertEq(vault.balanceOfEmissions(USER, _epochId), 10 ether - relayerFee); // test relayer balance assertEq(IERC20(UNDERLYING).balanceOf(relayer), relayerFee * 1); @@ -141,9 +140,7 @@ contract CarouselTest is Helper { // please check logs: test forge test -m testDepositInQueue -vvvv vault.mintDepositInQueue(_epochId, 230000); assertEq(vault.balanceOf(USER, _epochId), 10 ether - relayerFee); - assertEq(vault.balanceOfEmissions(USER, _epochId), 10 ether - relayerFee); assertEq(vault.balanceOf(USER2, _epochId), 10 ether - relayerFee); - assertEq(vault.balanceOfEmissions(USER2, _epochId), 10 ether - relayerFee); } function testEnListInRollover() public { @@ -245,17 +242,11 @@ contract CarouselTest is Helper { // check balances assertEq(vault.balanceOf(USER, _epochId), 10 ether - relayerFee); - assertEq(vault.balanceOfEmissions(USER, _epochId), 10 ether - relayerFee); assertEq(vault.balanceOf(USER2, _epochId), 10 ether - relayerFee); - assertEq(vault.balanceOfEmissions(USER2, _epochId), 10 ether - relayerFee); assertEq(vault.balanceOf(USER3, _epochId), 10 ether - relayerFee); - assertEq(vault.balanceOfEmissions(USER3, _epochId), 10 ether - relayerFee); assertEq(vault.balanceOf(USER4, _epochId), 10 ether - relayerFee); - assertEq(vault.balanceOfEmissions(USER4, _epochId), 10 ether - relayerFee); assertEq(vault.balanceOf(USER5, _epochId), 10 ether - relayerFee); - assertEq(vault.balanceOfEmissions(USER5, _epochId), 10 ether - relayerFee); assertEq(vault.balanceOf(USER6, _epochId), 10 ether - relayerFee); - assertEq(vault.balanceOfEmissions(USER6, _epochId), 10 ether - relayerFee); } function testRolloverMultiple() public { @@ -307,9 +298,7 @@ contract CarouselTest is Helper { // check balances assertEq(vault.balanceOf(USER, _epochId), 0); - assertEq(vault.balanceOfEmissions(USER, _epochId), 0); assertEq(vault.balanceOf(USER2, _epochId), 0); - assertEq(vault.balanceOfEmissions(USER2, _epochId), 0); // simulate prev epoch win stdstore @@ -340,19 +329,11 @@ contract CarouselTest is Helper { assertEq(((prevEpochSharesValueAfterRollover >> 1) << 1) , (((prevEpochShareValue) - (prevEpochUserBalance) - 16) >> 1) << 1); // zero out last bit to avoid rounding errors // check balances assertEq(vault.balanceOf(USER, _epochId), prevEpochUserBalance - relayerFeeInShares ); - assertEq(vault.balanceOfEmissions(USER, _epochId), prevEpochUserBalance - relayerFeeInShares); assertEq(vault.balanceOf(USER2, _epochId), prevEpochUserBalance - relayerFeeInShares); - assertEq(vault.balanceOfEmissions(USER2, _epochId), prevEpochUserBalance - relayerFeeInShares); assertEq(vault.balanceOf(USER3, _epochId), prevEpochUserBalance - relayerFeeInShares); - assertEq(vault.balanceOfEmissions(USER3, _epochId), prevEpochUserBalance - relayerFeeInShares); assertEq(vault.balanceOf(USER4, _epochId), prevEpochUserBalance - relayerFeeInShares); - assertEq(vault.balanceOfEmissions(USER4, _epochId), prevEpochUserBalance - relayerFeeInShares); assertEq(vault.balanceOf(USER5, _epochId), prevEpochUserBalance - relayerFeeInShares); - assertEq(vault.balanceOfEmissions(USER5, _epochId), prevEpochUserBalance - relayerFeeInShares); - assertEq(vault.balanceOf(USER6, _epochId), prevEpochUserBalance - relayerFeeInShares); - assertEq(vault.balanceOfEmissions(USER6, _epochId), prevEpochUserBalance - relayerFeeInShares); - - + assertEq(vault.balanceOf(USER6, _epochId), prevEpochUserBalance - relayerFeeInShares); } diff --git a/test/V2/FactoryV2Test.t.sol b/test/V2/FactoryV2Test.t.sol index 96f4b59d..e8289788 100644 --- a/test/V2/FactoryV2Test.t.sol +++ b/test/V2/FactoryV2Test.t.sol @@ -7,6 +7,272 @@ import "../../src/v2/VaultV2.sol"; import "../../src/v2/TimeLock.sol"; import "../../src/v2/interfaces/IVaultV2.sol"; +contract TimeLockV1 { + mapping(bytes32 => bool) public queued; + + address public policy; + + uint256 public constant MIN_DELAY = 7 days; + uint256 public constant MAX_DELAY = 30 days; + uint256 public constant GRACE_PERIOD = 14 days; + + error NotOwner(address sender); + error AlreadyQueuedError(bytes32 txId); + error TimestampNotInRangeError(uint256 blocktimestamp, uint256 timestamp); + error NotQueuedError(bytes32 txId); + error TimestampNotPassedError(uint256 blocktimestamp, uint256 timestamp); + error TimestampExpiredError(uint256 blocktimestamp, uint256 timestamp); + error TxFailedError(string func); + + event Queue( + bytes32 indexed txId, + address indexed target, + string func, + uint256 index, + uint256 data, + address to, + address token, + uint256 timestamp + ); + + event Execute( + bytes32 indexed txId, + address indexed target, + string func, + uint256 index, + uint256 data, + address to, + address token, + uint256 timestamp + ); + + event Delete( + bytes32 indexed txId, + address indexed target, + string func, + uint256 index, + uint256 data, + address to, + address token, + uint256 timestamp + ); + + modifier onlyOwner() { + if (msg.sender != policy) revert NotOwner(msg.sender); + _; + } + + constructor(address _policy) { + policy = _policy; + } + + /** + * @dev leave params zero if not using them + * @notice Queue a transaction + * @param _target The target contract + * @param _func The function to call + * @param _index The market index of the vault to call the function on + * @param _data The data to pass to the function + * @param _to The address to change the params to + * @param _token The token to change the params to + * @param _timestamp The timestamp to execute the transaction + */ + function queue( + address _target, + string calldata _func, + uint256 _index, + uint256 _data, + address _to, + address _token, + uint256 _timestamp + ) external onlyOwner { + //create tx id + bytes32 txId = getTxId( + _target, + _func, + _index, + _data, + _to, + _token, + _timestamp + ); + + //check tx id unique + if (queued[txId]) { + revert AlreadyQueuedError(txId); + } + + //check timestamp + if ( + _timestamp < block.timestamp + MIN_DELAY || + _timestamp > block.timestamp + MAX_DELAY + ) { + revert TimestampNotInRangeError(block.timestamp, _timestamp); + } + + //queue tx + queued[txId] = true; + + emit Queue( + txId, + _target, + _func, + _index, + _data, + _to, + _token, + _timestamp + ); + } + + /** + * @dev leave params zero if not using them + * @notice Execute a Queued a transaction + * @param _target The target contract + * @param _func The function to call + * @param _index The market index of the vault to call the function on + * @param _data The data to pass to the function + * @param _to The address to change the params to + * @param _token The token to change the params to + * @param _timestamp The timestamp after which to execute the transaction + */ + function execute( + address _target, + string calldata _func, + uint256 _index, + uint256 _data, + address _to, + address _token, + uint256 _timestamp + ) external onlyOwner { + bytes32 txId = getTxId( + _target, + _func, + _index, + _data, + _to, + _token, + _timestamp + ); + + //check tx id queued + if (!queued[txId]) { + revert NotQueuedError(txId); + } + + //check block.timestamp > timestamp + if (block.timestamp < _timestamp) { + revert TimestampNotPassedError(block.timestamp, _timestamp); + } + if (block.timestamp > _timestamp + GRACE_PERIOD) { + revert TimestampExpiredError( + block.timestamp, + _timestamp + GRACE_PERIOD + ); + } + + //delete tx from queue + queued[txId] = false; + + //execute tx + if (compareStringsbyBytes(_func, "changeTreasury")) { + // VaultFactoryV2(_target).changeTreasury(_to, _index); + } else if (compareStringsbyBytes(_func, "changeController")) { + VaultFactoryV2(_target).changeController(_index, _to); + } else if (compareStringsbyBytes(_func, "changeOracle")) { + VaultFactoryV2(_target).changeOracle(_token, _to); + } else { + revert TxFailedError(_func); + } + + emit Execute( + txId, + _target, + _func, + _index, + _data, + _to, + _token, + _timestamp + ); + } + + function cancel( + address _target, + string calldata _func, + uint256 _index, + uint256 _data, + address _to, + address _token, + uint256 _timestamp + ) external onlyOwner { + bytes32 txId = getTxId( + _target, + _func, + _index, + _data, + _to, + _token, + _timestamp + ); + + //check tx id queued + if (!queued[txId]) { + revert NotQueuedError(txId); + } + + //delete tx from queue + queued[txId] = false; + + emit Delete( + txId, + _target, + _func, + _index, + _data, + _to, + _token, + _timestamp + ); + } + + function getTxId( + address _target, + string calldata _func, + uint256 _index, + uint256 _data, + address _to, + address _token, + uint256 _timestamp + ) public pure returns (bytes32 txId) { + return + keccak256( + abi.encode( + _target, + _func, + _index, + _data, + _to, + _token, + _timestamp + ) + ); + } + + function compareStringsbyBytes(string memory s1, string memory s2) + public + pure + returns (bool) + { + return + keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2)); + } + + function changeOwner(address _newOwner) external onlyOwner { + policy = _newOwner; + } +} + contract FactoryV2Test is Helper { VaultFactoryV2 factory; address controller; @@ -24,6 +290,66 @@ contract FactoryV2Test is Helper { factory.whitelistController(address(controller)); } + function testOneTimelock() public { + string memory arbitrumRpcUrl = vm.envString("ARBITRUM_RPC_URL"); + uint256 arbForkId = vm.createFork(arbitrumRpcUrl); + vm.selectFork(arbForkId); + + TimeLockV1 t = TimeLockV1(0xdf468f3FCCa9FC6Cb51241A139a2Eb53971D8f81); + factory = VaultFactoryV2(0x984E0EB8fB687aFa53fc8B33E12E04967560E092); + bytes memory data = bytes("0x4dc809ce0000000000000000000000005979d7b546e38e414f7e9822514be443a4800529000000000000000000000000ded2c52b75b24732e9107377b7ba93ec1ffa4baf"); + // immulate timelocker address + vm.startPrank(0x16cBaDA408F7523452fF91c8387b1784d00d10D8); + + uint256 timestamp = block.timestamp + 7 days + 1 seconds; + + t.queue( + address(factory), + "changeOracle", + 0, + 0, + 0xded2c52b75B24732e9107377B7Ba93eC1fFa4BAf, + 0x5979D7b546E38E414F7E9822514be443A4800529, + timestamp + ); + + bytes32 txId = t.getTxId( + address(factory), + "changeOracle", + 0, + 0, + 0xded2c52b75B24732e9107377B7Ba93eC1fFa4BAf, + 0x5979D7b546E38E414F7E9822514be443A4800529, + timestamp + ); + + vm.warp(timestamp - 1 seconds); + + console.logBytes32(txId); + + t.execute( + address(factory), + "changeOracle", + 0, + 0, + 0xded2c52b75B24732e9107377B7Ba93eC1fFa4BAf, + 0x5979D7b546E38E414F7E9822514be443A4800529, + timestamp + ); + + address newOracle = factory.tokenToOracle(0x5979D7b546E38E414F7E9822514be443A4800529); + + console.log(newOracle); + + + assertTrue(newOracle == 0xded2c52b75B24732e9107377B7Ba93eC1fFa4BAf); + + + // t.executeTransaction(address(factory), 0, data); + // 0xdf468f3fcca9fc6cb51241a139a2eb53971d8f81 + + + } function testFactoryCreation() public { diff --git a/test/V2/e2e/EndToEndCarouselTest.t.sol b/test/V2/e2e/EndToEndCarouselTest.t.sol index 28dc672a..138e6427 100644 --- a/test/V2/e2e/EndToEndCarouselTest.t.sol +++ b/test/V2/e2e/EndToEndCarouselTest.t.sol @@ -174,13 +174,9 @@ contract EndToEndCarouselTest is Helper { //assert balance and emissions assertEq(Carousel(collateral).balanceOf(USER, epochId), collatBalanceAfterFee - relayerFee); - assertEq(Carousel(collateral).balanceOfEmissions(USER, epochId), collatBalanceAfterFee - relayerFee); assertEq(Carousel(collateral).balanceOf(USER2, epochId), collatBalanceAfterFee - relayerFee); - assertEq(Carousel(collateral).balanceOfEmissions(USER2, epochId), collatBalanceAfterFee - relayerFee); assertEq(Carousel(premium).balanceOf(USER, epochId), premiumBalanceAfterFee - relayerFee); - assertEq(Carousel(premium).balanceOfEmissions(USER, epochId), premiumBalanceAfterFee - relayerFee); assertEq(Carousel(premium).balanceOf(USER2, epochId), 0); - assertEq(Carousel(premium).balanceOfEmissions(USER2, epochId), 0); vm.startPrank(USER); From ca74f10b80aaa0071772a790ba410471ad2b3a25 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Tue, 18 Apr 2023 19:04:11 +0200 Subject: [PATCH 20/31] remove token to oracle and replace with market to oracle mapping --- script/v2/V2DeploymentScript.s.sol | 34 +- src/v2/Carousel/CarouselFactory.sol | 16 +- .../Controllers/ControllerPeggedAssetV2.sol | 8 +- src/v2/VaultFactoryV2.sol | 24 +- src/v2/interfaces/IVaultFactoryV2.sol | 2 +- test/V2/Carousel/CarouselFactoryTest.t.sol | 2 +- .../ControllerPeggedAssetV2Test.t.sol | 4 +- test/V2/FactoryV2Test.t.sol | 345 +----------------- 8 files changed, 72 insertions(+), 363 deletions(-) diff --git a/script/v2/V2DeploymentScript.s.sol b/script/v2/V2DeploymentScript.s.sol index f1342c83..d7f5c87c 100644 --- a/script/v2/V2DeploymentScript.s.sol +++ b/script/v2/V2DeploymentScript.s.sol @@ -66,6 +66,9 @@ contract V2DeploymentScript is Script, HelperV2 { treasury = msg.sender; + console2.log("Broadcast policy", policy); + console2.log("Broadcast treasury", treasury); + // address timeLock = address(new TimeLock(policy)); @@ -86,15 +89,38 @@ contract V2DeploymentScript is Script, HelperV2 { // IERC20(emissionToken).approve(0x1A5151C53bb041A7f70B40adfAEFe0FDfE05b2d8, 200 ether); - CarouselFactory(0x1A5151C53bb041A7f70B40adfAEFe0FDfE05b2d8).createEpochWithEmissions( - uint256(79901062978974686921194727646590599359178698799258240092258231289348051120802), - 1681494640, - 1681581040, + + ( address prem, address collat, uint256 marketId) = CarouselFactory(0x3BDB1eA3912121627da97F574d1Cb5E82FeF353B).createNewCarouselMarket( + CarouselFactory.CarouselMarketConfigurationCalldata( + addresses.tokenDAI, + 1 ether - 1, + addresses.oracleDAI, + weth, + "y2kDAI_999*", + "https://y2k.finance", + 0x01964e70ED9bA452c99932f46f302B10d2dAb2C9, + 1 gwei, + 10, + 1 ether + ) + ); + + console.log("Prem", prem); + console.log("Collat", collat); + console.log("marketId", marketId); + + + (uint256 eId, ) = CarouselFactory(0x3BDB1eA3912121627da97F574d1Cb5E82FeF353B).createEpochWithEmissions( + marketId, + 1681841850, + 1682187450, 50, 0, 0 ); + console.log("eId", eId); + //stop setUp(); // console2.log("Controller address", address(controller)); diff --git a/src/v2/Carousel/CarouselFactory.sol b/src/v2/Carousel/CarouselFactory.sol index ce62560f..2d48dfa8 100644 --- a/src/v2/Carousel/CarouselFactory.sol +++ b/src/v2/Carousel/CarouselFactory.sol @@ -54,15 +54,21 @@ contract CarouselFactory is VaultFactoryV2 { if (_marketCalldata.token == address(0)) revert AddressZero(); if (_marketCalldata.oracle == address(0)) revert AddressZero(); if (_marketCalldata.underlyingAsset == address(0)) revert AddressZero(); - - if (tokenToOracle[_marketCalldata.token] == address(0)) { - tokenToOracle[_marketCalldata.token] = _marketCalldata.oracle; - } - + marketId = getMarketId(_marketCalldata.token, _marketCalldata.strike, _marketCalldata.underlyingAsset); + if (marketIdToVaults[marketId][0] != address(0)) revert MarketAlreadyExists(); + + marketIdInfo[marketId] = MarketInfo( + _marketCalldata.token, + _marketCalldata.strike, + _marketCalldata.underlyingAsset + ); + // set oracle for the market + marketToOracle[marketId] = _marketCalldata.oracle; + //y2kUSDC_99*PREMIUM premium = CarouselCreator.createCarousel( CarouselCreator.CarouselMarketConfiguration( diff --git a/src/v2/Controllers/ControllerPeggedAssetV2.sol b/src/v2/Controllers/ControllerPeggedAssetV2.sol index 2e132ae7..5e948d98 100644 --- a/src/v2/Controllers/ControllerPeggedAssetV2.sol +++ b/src/v2/Controllers/ControllerPeggedAssetV2.sol @@ -60,7 +60,7 @@ contract ControllerPeggedAssetV2 { if (premiumVault.epochExists(_epochId) == false) revert EpochNotExist(); - int256 price = getLatestPrice(premiumVault.token()); + int256 price = getLatestPrice(_marketId); if (int256(premiumVault.strike()) <= price) revert PriceNotAtStrikePrice(price); @@ -275,10 +275,10 @@ contract ControllerPeggedAssetV2 { GETTERS //////////////////////////////////////////////////////////////*/ /** @notice Lookup token price - * @param _token Target token address + * @param _marketId Target token address * @return nowPrice Current token price */ - function getLatestPrice(address _token) public view returns (int256) { + function getLatestPrice(uint256 _marketId) public view returns (int256) { ( , /*uint80 roundId*/ @@ -303,7 +303,7 @@ contract ControllerPeggedAssetV2 { } AggregatorV3Interface priceFeed = AggregatorV3Interface( - vaultFactory.tokenToOracle(_token) + vaultFactory.marketToOracle(_marketId) ); (uint80 roundID, int256 price, ,uint256 updatedAt, uint80 answeredInRound) = priceFeed .latestRoundData(); diff --git a/src/v2/VaultFactoryV2.sol b/src/v2/VaultFactoryV2.sol index 6327060b..059a12ef 100644 --- a/src/v2/VaultFactoryV2.sol +++ b/src/v2/VaultFactoryV2.sol @@ -24,7 +24,7 @@ contract VaultFactoryV2 is Ownable { mapping(uint256 => uint256[]) public marketIdToEpochs; //all epochs in the market mapping(uint256 => MarketInfo) public marketIdInfo; // marketId configuration mapping(uint256 => uint16) public epochFee; // epochId to fee - mapping(address => address) public tokenToOracle; //token address to respective oracle smart contract address + mapping(uint256 => address) public marketToOracle; //token address to respective oracle smart contract address mapping(address => bool) public controllers; /*////////////////////////////////////////////////////////////// @@ -82,9 +82,7 @@ contract VaultFactoryV2 is Ownable { if (_marketCalldata.oracle == address(0)) revert AddressZero(); if (_marketCalldata.underlyingAsset == address(0)) revert AddressZero(); - if (tokenToOracle[_marketCalldata.token] == address(0)) { - tokenToOracle[_marketCalldata.token] = _marketCalldata.oracle; - } + marketId = getMarketId(_marketCalldata.token, _marketCalldata.strike, _marketCalldata.underlyingAsset); marketIdInfo[marketId] = MarketInfo( @@ -95,6 +93,9 @@ contract VaultFactoryV2 is Ownable { if (marketIdToVaults[marketId][0] != address(0)) revert MarketAlreadyExists(); + + // set oracle for the market + marketToOracle[marketId] = _marketCalldata.oracle; //y2kUSDC_99*PREMIUM premium = VaultV2Creator.createVaultV2( @@ -313,18 +314,19 @@ contract VaultFactoryV2 is Ownable { /** @notice Timelocker function, changes oracle address for a given token - @param _token Target token address + @param _marketId Target token address @param _oracle Oracle address */ - function changeOracle(address _token, address _oracle) + function changeOracle(uint256 _marketId, address _oracle) public onlyTimeLocker { if (_oracle == address(0)) revert AddressZero(); - if (_token == address(0)) revert AddressZero(); + if(_marketId == 0) revert MarketDoesNotExist(_marketId); + if (marketToOracle[_marketId] == address(0)) revert MarketDoesNotExist(_marketId); - tokenToOracle[_token] = _oracle; - emit OracleChanged(_token, _oracle); + marketToOracle[_marketId] = _oracle; + emit OracleChanged(_marketId, _oracle); } /** @@ -545,10 +547,10 @@ contract VaultFactoryV2 is Ownable { ); /** @notice Oracle is changed when event is emitted - * @param _token Target token address + * @param _marketId Target token address * @param _oracle Target oracle address */ - event OracleChanged(address indexed _token, address _oracle); + event OracleChanged(uint256 indexed _marketId, address _oracle); /** @notice Address whitelisted is changed when event is emitted * @param _wAddress whitelisted address diff --git a/src/v2/interfaces/IVaultFactoryV2.sol b/src/v2/interfaces/IVaultFactoryV2.sol index 51879747..65819776 100644 --- a/src/v2/interfaces/IVaultFactoryV2.sol +++ b/src/v2/interfaces/IVaultFactoryV2.sol @@ -17,5 +17,5 @@ interface IVaultFactoryV2 { function getEpochFee(uint256) external view returns (uint16); - function tokenToOracle(address token) external view returns (address); + function marketToOracle(uint256 _marketId) external view returns (address); } diff --git a/test/V2/Carousel/CarouselFactoryTest.t.sol b/test/V2/Carousel/CarouselFactoryTest.t.sol index 302a9f83..5dfab297 100644 --- a/test/V2/Carousel/CarouselFactoryTest.t.sol +++ b/test/V2/Carousel/CarouselFactoryTest.t.sol @@ -71,7 +71,7 @@ contract CarouselFactoryTest is Helper { assertEq(factory.getVaults(marketId)[1], collateral); // test oracle is set - assertTrue(factory.tokenToOracle(token) == oracle); + assertTrue(factory.marketToOracle(marketId) == oracle); assertEq(marketId, factory.getMarketId(token, strike, underlying)); // test if counterparty is set diff --git a/test/V2/Controllers/ControllerPeggedAssetV2Test.t.sol b/test/V2/Controllers/ControllerPeggedAssetV2Test.t.sol index 6fc2d348..927c0ea9 100644 --- a/test/V2/Controllers/ControllerPeggedAssetV2Test.t.sol +++ b/test/V2/Controllers/ControllerPeggedAssetV2Test.t.sol @@ -92,8 +92,8 @@ contract ControllerPeggedAssetV2Test is Helper { // revert cases stdstore .target(address(factory)) - .sig("tokenToOracle(address)") - .with_key(TOKEN) + .sig("marketToOracle(uint256)") + .with_key(marketId) .checked_write(address(this)); // set oracle with faulty updated at time vm.warp(begin + 1); diff --git a/test/V2/FactoryV2Test.t.sol b/test/V2/FactoryV2Test.t.sol index e8289788..0642d73e 100644 --- a/test/V2/FactoryV2Test.t.sol +++ b/test/V2/FactoryV2Test.t.sol @@ -7,272 +7,6 @@ import "../../src/v2/VaultV2.sol"; import "../../src/v2/TimeLock.sol"; import "../../src/v2/interfaces/IVaultV2.sol"; -contract TimeLockV1 { - mapping(bytes32 => bool) public queued; - - address public policy; - - uint256 public constant MIN_DELAY = 7 days; - uint256 public constant MAX_DELAY = 30 days; - uint256 public constant GRACE_PERIOD = 14 days; - - error NotOwner(address sender); - error AlreadyQueuedError(bytes32 txId); - error TimestampNotInRangeError(uint256 blocktimestamp, uint256 timestamp); - error NotQueuedError(bytes32 txId); - error TimestampNotPassedError(uint256 blocktimestamp, uint256 timestamp); - error TimestampExpiredError(uint256 blocktimestamp, uint256 timestamp); - error TxFailedError(string func); - - event Queue( - bytes32 indexed txId, - address indexed target, - string func, - uint256 index, - uint256 data, - address to, - address token, - uint256 timestamp - ); - - event Execute( - bytes32 indexed txId, - address indexed target, - string func, - uint256 index, - uint256 data, - address to, - address token, - uint256 timestamp - ); - - event Delete( - bytes32 indexed txId, - address indexed target, - string func, - uint256 index, - uint256 data, - address to, - address token, - uint256 timestamp - ); - - modifier onlyOwner() { - if (msg.sender != policy) revert NotOwner(msg.sender); - _; - } - - constructor(address _policy) { - policy = _policy; - } - - /** - * @dev leave params zero if not using them - * @notice Queue a transaction - * @param _target The target contract - * @param _func The function to call - * @param _index The market index of the vault to call the function on - * @param _data The data to pass to the function - * @param _to The address to change the params to - * @param _token The token to change the params to - * @param _timestamp The timestamp to execute the transaction - */ - function queue( - address _target, - string calldata _func, - uint256 _index, - uint256 _data, - address _to, - address _token, - uint256 _timestamp - ) external onlyOwner { - //create tx id - bytes32 txId = getTxId( - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ); - - //check tx id unique - if (queued[txId]) { - revert AlreadyQueuedError(txId); - } - - //check timestamp - if ( - _timestamp < block.timestamp + MIN_DELAY || - _timestamp > block.timestamp + MAX_DELAY - ) { - revert TimestampNotInRangeError(block.timestamp, _timestamp); - } - - //queue tx - queued[txId] = true; - - emit Queue( - txId, - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ); - } - - /** - * @dev leave params zero if not using them - * @notice Execute a Queued a transaction - * @param _target The target contract - * @param _func The function to call - * @param _index The market index of the vault to call the function on - * @param _data The data to pass to the function - * @param _to The address to change the params to - * @param _token The token to change the params to - * @param _timestamp The timestamp after which to execute the transaction - */ - function execute( - address _target, - string calldata _func, - uint256 _index, - uint256 _data, - address _to, - address _token, - uint256 _timestamp - ) external onlyOwner { - bytes32 txId = getTxId( - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ); - - //check tx id queued - if (!queued[txId]) { - revert NotQueuedError(txId); - } - - //check block.timestamp > timestamp - if (block.timestamp < _timestamp) { - revert TimestampNotPassedError(block.timestamp, _timestamp); - } - if (block.timestamp > _timestamp + GRACE_PERIOD) { - revert TimestampExpiredError( - block.timestamp, - _timestamp + GRACE_PERIOD - ); - } - - //delete tx from queue - queued[txId] = false; - - //execute tx - if (compareStringsbyBytes(_func, "changeTreasury")) { - // VaultFactoryV2(_target).changeTreasury(_to, _index); - } else if (compareStringsbyBytes(_func, "changeController")) { - VaultFactoryV2(_target).changeController(_index, _to); - } else if (compareStringsbyBytes(_func, "changeOracle")) { - VaultFactoryV2(_target).changeOracle(_token, _to); - } else { - revert TxFailedError(_func); - } - - emit Execute( - txId, - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ); - } - - function cancel( - address _target, - string calldata _func, - uint256 _index, - uint256 _data, - address _to, - address _token, - uint256 _timestamp - ) external onlyOwner { - bytes32 txId = getTxId( - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ); - - //check tx id queued - if (!queued[txId]) { - revert NotQueuedError(txId); - } - - //delete tx from queue - queued[txId] = false; - - emit Delete( - txId, - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ); - } - - function getTxId( - address _target, - string calldata _func, - uint256 _index, - uint256 _data, - address _to, - address _token, - uint256 _timestamp - ) public pure returns (bytes32 txId) { - return - keccak256( - abi.encode( - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ) - ); - } - - function compareStringsbyBytes(string memory s1, string memory s2) - public - pure - returns (bool) - { - return - keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2)); - } - - function changeOwner(address _newOwner) external onlyOwner { - policy = _newOwner; - } -} - contract FactoryV2Test is Helper { VaultFactoryV2 factory; address controller; @@ -290,67 +24,6 @@ contract FactoryV2Test is Helper { factory.whitelistController(address(controller)); } - function testOneTimelock() public { - string memory arbitrumRpcUrl = vm.envString("ARBITRUM_RPC_URL"); - uint256 arbForkId = vm.createFork(arbitrumRpcUrl); - vm.selectFork(arbForkId); - - TimeLockV1 t = TimeLockV1(0xdf468f3FCCa9FC6Cb51241A139a2Eb53971D8f81); - factory = VaultFactoryV2(0x984E0EB8fB687aFa53fc8B33E12E04967560E092); - bytes memory data = bytes("0x4dc809ce0000000000000000000000005979d7b546e38e414f7e9822514be443a4800529000000000000000000000000ded2c52b75b24732e9107377b7ba93ec1ffa4baf"); - // immulate timelocker address - vm.startPrank(0x16cBaDA408F7523452fF91c8387b1784d00d10D8); - - uint256 timestamp = block.timestamp + 7 days + 1 seconds; - - t.queue( - address(factory), - "changeOracle", - 0, - 0, - 0xded2c52b75B24732e9107377B7Ba93eC1fFa4BAf, - 0x5979D7b546E38E414F7E9822514be443A4800529, - timestamp - ); - - bytes32 txId = t.getTxId( - address(factory), - "changeOracle", - 0, - 0, - 0xded2c52b75B24732e9107377B7Ba93eC1fFa4BAf, - 0x5979D7b546E38E414F7E9822514be443A4800529, - timestamp - ); - - vm.warp(timestamp - 1 seconds); - - console.logBytes32(txId); - - t.execute( - address(factory), - "changeOracle", - 0, - 0, - 0xded2c52b75B24732e9107377B7Ba93eC1fFa4BAf, - 0x5979D7b546E38E414F7E9822514be443A4800529, - timestamp - ); - - address newOracle = factory.tokenToOracle(0x5979D7b546E38E414F7E9822514be443A4800529); - - console.log(newOracle); - - - assertTrue(newOracle == 0xded2c52b75B24732e9107377B7Ba93eC1fFa4BAf); - - - // t.executeTransaction(address(factory), 0, data); - // 0xdf468f3fcca9fc6cb51241a139a2eb53971d8f81 - - - } - function testFactoryCreation() public { TimeLock timelock = new TimeLock(ADMIN); @@ -485,7 +158,7 @@ contract FactoryV2Test is Helper { assertEq(factory.getVaults(marketId)[1], collateral); // test oracle is set - assertTrue(factory.tokenToOracle(token) == oracle); + assertTrue(factory.marketToOracle(marketId) == oracle); assertEq(marketId, factory.getMarketId(token, strike, underlying)); // test if counterparty is set @@ -635,21 +308,23 @@ contract FactoryV2Test is Helper { // address oldOracle = address(0x3); address newOracle = address(0x4); - createMarketHelper(); + uint256 marketId = createMarketHelper(); vm.expectRevert(VaultFactoryV2.NotTimeLocker.selector); - factory.changeOracle(token,newOracle); + factory.changeOracle(marketId,newOracle); vm.startPrank(address(factory.timelocker())); + vm.expectRevert(abi.encodeWithSelector(VaultFactoryV2.MarketDoesNotExist.selector, uint256(0))); + factory.changeOracle(uint256(0), newOracle); + vm.expectRevert(abi.encodeWithSelector(VaultFactoryV2.MarketDoesNotExist.selector, uint256(1))); + factory.changeOracle(uint256(1), newOracle); vm.expectRevert(VaultFactoryV2.AddressZero.selector); - factory.changeOracle(address(0), newOracle); - vm.expectRevert(VaultFactoryV2.AddressZero.selector); - factory.changeOracle(token, address(0)); + factory.changeOracle(marketId, address(0)); // test success case - factory.changeOracle(token, newOracle); + factory.changeOracle(marketId, newOracle); vm.stopPrank(); - assertEq(factory.tokenToOracle(token), newOracle); + assertEq(factory.marketToOracle(marketId), newOracle); } function createMarketHelper() public returns(uint256 marketId){ From 35912e5ed3a7d837c5a323bcc95cf2c794ceb230 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Sun, 23 Apr 2023 16:11:04 -0700 Subject: [PATCH 21/31] adjust deployment script --- script/v2/V2DeploymentScript.s.sol | 47 +++++++++++++++++------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/script/v2/V2DeploymentScript.s.sol b/script/v2/V2DeploymentScript.s.sol index d7f5c87c..a41b5882 100644 --- a/script/v2/V2DeploymentScript.s.sol +++ b/script/v2/V2DeploymentScript.s.sol @@ -29,6 +29,7 @@ contract V2DeploymentScript is Script, HelperV2 { address weth = 0x6BE37a65E46048B1D12C0E08d9722402A5247Ff1; address treasury = 0xCCA23C05a9Cf7e78830F3fd55b1e8CfCCbc5E50F; address emissionToken = 0x5D59e5837F7e5d0F710178Eda34d9eCF069B36D2; + address factory; address controller; function run() public { @@ -73,6 +74,9 @@ contract V2DeploymentScript is Script, HelperV2 { // address timeLock = address(new TimeLock(policy)); // CarouselFactory vaultFactory = new CarouselFactory(weth, treasury, policy, emissionToken); + factory = 0xAd2f15ff7d167c800281ef52fa098Fae33429cc6; + + controller = 0xDf878548b17429a6e6a3ff66Fb629e347738aA56; // VaultFactoryV2 vaultFactory = new VaultFactoryV2(weth, treasury, timeLock); // console2.log("Broadcast admin ", addresses.admin); @@ -82,44 +86,47 @@ contract V2DeploymentScript is Script, HelperV2 { // vaultFactory = new VaultFactory(addresses.treasury, addresses.weth, addresses.policy); // controller = address(new ControllerPeggedAssetV2(address(vaultFactory), addresses.arbitrum_sequencer, treasury)); - // vaultFactory.whitelistController(address(controller)); + // vaultFactory.whitelistController(controller); + + console.log("factory", factory); + console.log("controller", controller); // deployMarketsV2(address(vaultFactory)); - // IERC20(emissionToken).approve(0x1A5151C53bb041A7f70B40adfAEFe0FDfE05b2d8, 200 ether); + // IERC20(emissionToken).approve(factory, 100 ether); - ( address prem, address collat, uint256 marketId) = CarouselFactory(0x3BDB1eA3912121627da97F574d1Cb5E82FeF353B).createNewCarouselMarket( + ( address prem, address collat, uint256 marketId) = CarouselFactory(factory).createNewCarouselMarket( CarouselFactory.CarouselMarketConfigurationCalldata( - addresses.tokenDAI, - 1 ether - 1, - addresses.oracleDAI, + addresses.tokenMIM, + 999000000000000000, + addresses.oracleMIM, weth, - "y2kDAI_999*", + "y2kMIM_999*", "https://y2k.finance", - 0x01964e70ED9bA452c99932f46f302B10d2dAb2C9, + controller, 1 gwei, 10, 1 ether ) ); - console.log("Prem", prem); - console.log("Collat", collat); - console.log("marketId", marketId); + // console.log("Prem", prem); + // console.log("Collat", collat); + // console.log("marketId", marketId); - (uint256 eId, ) = CarouselFactory(0x3BDB1eA3912121627da97F574d1Cb5E82FeF353B).createEpochWithEmissions( - marketId, - 1681841850, - 1682187450, - 50, - 0, - 0 - ); + // (uint256 eId, ) = CarouselFactory(factory).createEpochWithEmissions( + // marketId, + // 1682532658, + // 1682705458, + // 50, + // 1 ether, + // 10 ether + // ); - console.log("eId", eId); + // console.log("eId", eId); //stop setUp(); From 7607153f48f458938724fb64b00a0b644cb6bf04 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Thu, 27 Apr 2023 10:44:14 -0700 Subject: [PATCH 22/31] fix queue deposit relayerFee change --- script/v2/V2DeploymentScript.s.sol | 44 +++++++++++++++--------------- src/v2/Carousel/Carousel.sol | 16 +++++++++-- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/script/v2/V2DeploymentScript.s.sol b/script/v2/V2DeploymentScript.s.sol index a41b5882..68b6cd98 100644 --- a/script/v2/V2DeploymentScript.s.sol +++ b/script/v2/V2DeploymentScript.s.sol @@ -97,34 +97,34 @@ contract V2DeploymentScript is Script, HelperV2 { // IERC20(emissionToken).approve(factory, 100 ether); - ( address prem, address collat, uint256 marketId) = CarouselFactory(factory).createNewCarouselMarket( - CarouselFactory.CarouselMarketConfigurationCalldata( - addresses.tokenMIM, - 999000000000000000, - addresses.oracleMIM, - weth, - "y2kMIM_999*", - "https://y2k.finance", - controller, - 1 gwei, - 10, - 1 ether - ) - ); + // ( address prem, address collat, uint256 marketId) = CarouselFactory(factory).createNewCarouselMarket( + // CarouselFactory.CarouselMarketConfigurationCalldata( + // addresses.tokenMIM, + // 999000000000000000, + // addresses.oracleMIM, + // weth, + // "y2kMIM_999*", + // "https://y2k.finance", + // controller, + // 1 gwei, + // 10, + // 1 ether + // ) + // ); // console.log("Prem", prem); // console.log("Collat", collat); // console.log("marketId", marketId); - // (uint256 eId, ) = CarouselFactory(factory).createEpochWithEmissions( - // marketId, - // 1682532658, - // 1682705458, - // 50, - // 1 ether, - // 10 ether - // ); + (uint256 eId, ) = CarouselFactory(factory).createEpochWithEmissions( + 50136727949622076191748106171773774901339026601219072444023567158965921292263, + 1682575989, + 1682748789, + 50, + 1 ether, + 2 ether + ); // console.log("eId", eId); diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index e1c27d0f..308fc162 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -311,6 +311,7 @@ contract Carousel is VaultV2 { // queue is executed from the tail to the head // get last index of queue uint256 i = length - 1; + uint256 relayerFeeShortfall; while ((length - _operations) <= i) { // this loop impelements FILO (first in last out) stack to reduce gas cost and improve code readability // changing it to FIFO (first in first out) would require more code changes and would be more expensive @@ -324,16 +325,25 @@ contract Carousel is VaultV2 { _asset().safeTransfer(treasury(), feeAmount); } + // remove minDeposit has chagned during QueueItem is in the queue and relayerFee is now higher than deposit amount + // mint 0 and pay relayerFeeShortfall to relayer + if(assetsToDeposit > relayerFee) { + assetsToDeposit -= relayerFee; + } else { + relayerFeeShortfall += (relayerFee - assetsToDeposit); + assetsToDeposit = 0; + } + _mintShares( queue[i].receiver, _epochId, - assetsToDeposit - relayerFee + assetsToDeposit ); emit Deposit( msg.sender, queue[i].receiver, _epochId, - assetsToDeposit - relayerFee + assetsToDeposit ); depositQueue.pop(); if (i == 0) break; @@ -344,7 +354,7 @@ contract Carousel is VaultV2 { emit RelayerMinted(_epochId, _operations); - asset.safeTransfer(msg.sender, _operations * relayerFee); + asset.safeTransfer(msg.sender, (_operations * relayerFee) - relayerFeeShortfall); } /** @notice mints for rollovers From ad388625e21e7527c22b16701474eff3d35f4d49 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Thu, 27 Apr 2023 10:48:15 -0700 Subject: [PATCH 23/31] lint --- src/v2/Carousel/Carousel.sol | 101 +++++++++------ src/v2/Carousel/CarouselFactory.sol | 40 +++--- .../Controllers/ControllerPeggedAssetV2.sol | 21 ++- src/v2/CustomERC1155/ERC1155.sol | 122 +++++++++++++++--- src/v2/CustomERC1155/ERC1155Supply.sol | 5 +- src/v2/SemiFungibleVault.sol | 4 +- src/v2/TimeLock.sol | 4 +- src/v2/VaultFactoryV2.sol | 57 ++++---- src/v2/VaultV2.sol | 7 +- src/v2/interfaces/IVaultV2.sol | 1 - 10 files changed, 237 insertions(+), 125 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index 308fc162..cd588abd 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -238,7 +238,7 @@ contract Carousel is VaultV2 { // check if user has enough balance if (balanceOf(_receiver, _epochId) < _assets) revert InsufficientBalance(); - + // check if user has already queued up a rollover if (isEnlistedInRolloverQueue(_receiver)) { uint256 index = getRolloverIndex(_receiver); @@ -257,7 +257,7 @@ contract Carousel is VaultV2 { // index will allways be higher than 0 ownerToRollOverQueueIndex[_receiver] = rolloverQueue.length; } - + emit RolloverQueued(_receiver, _assets, _epochId); } @@ -265,11 +265,10 @@ contract Carousel is VaultV2 { @param _owner address that is delisting from rollover queue */ function delistInRollover(address _owner) public { - // @note + // @note // its not possible for users to delete the QueueItem from the array because // during rollover, earlier users in rollover queue, can grief attack later users by deleting their queue item // instead we just set the assets to 0 and the epochId to 0 as a flag to indicate that the user is no longer in the queue - // check if user is enlisted in rollover queue if (!isEnlistedInRolloverQueue(_owner)) revert NoRolloverQueued(); @@ -283,7 +282,6 @@ contract Carousel is VaultV2 { uint256 index = getRolloverIndex(_owner); rolloverQueue[index].assets = 0; rolloverQueue[index].epochId = 0; - } /** @notice mints deposit in rollover queue @@ -320,25 +318,24 @@ contract Carousel is VaultV2 { uint256 assetsToDeposit = queue[i].assets; if (depositFee > 0) { - (uint256 feeAmount, uint256 assetsAfterFee) = getEpochDepositFee(_epochId, assetsToDeposit); + ( + uint256 feeAmount, + uint256 assetsAfterFee + ) = getEpochDepositFee(_epochId, assetsToDeposit); assetsToDeposit = assetsAfterFee; _asset().safeTransfer(treasury(), feeAmount); } - // remove minDeposit has chagned during QueueItem is in the queue and relayerFee is now higher than deposit amount + // if minDeposit has chagned during QueueItem is in the queue and relayerFee is now higher than deposit amount // mint 0 and pay relayerFeeShortfall to relayer - if(assetsToDeposit > relayerFee) { - assetsToDeposit -= relayerFee; + if (assetsToDeposit > relayerFee) { + assetsToDeposit -= relayerFee; } else { relayerFeeShortfall += (relayerFee - assetsToDeposit); assetsToDeposit = 0; } - _mintShares( - queue[i].receiver, - _epochId, - assetsToDeposit - ); + _mintShares(queue[i].receiver, _epochId, assetsToDeposit); emit Deposit( msg.sender, queue[i].receiver, @@ -354,7 +351,10 @@ contract Carousel is VaultV2 { emit RelayerMinted(_epochId, _operations); - asset.safeTransfer(msg.sender, (_operations * relayerFee) - relayerFeeShortfall); + asset.safeTransfer( + msg.sender, + (_operations * relayerFee) - relayerFeeShortfall + ); } /** @notice mints for rollovers @@ -394,10 +394,10 @@ contract Carousel is VaultV2 { uint256 executions = 0; while ((index - prevIndex) < (_operations)) { - // only roll over if last epoch is resolved and user rollover position is valid - if (epochResolved[queue[index].epochId] && queue[index].assets > 0) { - + if ( + epochResolved[queue[index].epochId] && queue[index].assets > 0 + ) { uint256 entitledAmount = previewWithdraw( queue[index].epochId, queue[index].assets @@ -406,7 +406,10 @@ contract Carousel is VaultV2 { // mint only if user won epoch he is rolling over if (entitledAmount > queue[index].assets) { // @note previewAmountInShares can only be called if epoch is in profit - uint256 relayerFeeInShares = previewAmountInShares(queue[index].epochId, relayerFee); + uint256 relayerFeeInShares = previewAmountInShares( + queue[index].epochId, + relayerFee + ); // skip the rollover for the user if the assets cannot cover the relayer fee instead of revert. if (queue[index].assets < relayerFeeInShares) { @@ -414,10 +417,14 @@ contract Carousel is VaultV2 { continue; } - // to calculate originalDepositValue get the diff between shares and value of shares - // convert this value amount value back to shares + // to calculate originalDepositValue get the diff between shares and value of shares + // convert this value amount value back to shares // subtract from assets - uint256 originalDepositValue = queue[index].assets - previewAmountInShares(queue[index].epochId, (entitledAmount - queue[index].assets)); + uint256 originalDepositValue = queue[index].assets - + previewAmountInShares( + queue[index].epochId, + (entitledAmount - queue[index].assets) + ); // @note we know shares were locked up to this point _burn( queue[index].receiver, @@ -445,7 +452,8 @@ contract Carousel is VaultV2 { originalDepositValue ) ); - uint256 assetsToMint = queue[index].assets - relayerFeeInShares; + uint256 assetsToMint = queue[index].assets - + relayerFeeInShares; _mintShares(queue[index].receiver, _epochId, assetsToMint); emit Deposit( msg.sender, @@ -489,7 +497,10 @@ contract Carousel is VaultV2 { uint256 assetsToDeposit = _assets; if (depositFee > 0) { - (uint256 feeAmount, uint256 assetsAfterFee) = getEpochDepositFee(_id, _assets); + ( + uint256 feeAmount, + uint256 assetsAfterFee + ) = getEpochDepositFee(_id, _assets); assetsToDeposit = assetsAfterFee; _asset().safeTransfer(treasury(), feeAmount); } @@ -519,12 +530,11 @@ contract Carousel is VaultV2 { _mint(to, id, amount, EMPTY); } - /*/////////////////////////////////////////////////////////////// ADMIN FUNCTIONS //////////////////////////////////////////////////////////////*/ - /** + /** @notice This function is called by the controller if the epoch has started, but the counterparty vault has no value. In this case the users can withdraw their deposit. Additionally, emissions are transferred to the treasury. @param _id uint256 identifier of the epoch */ @@ -536,13 +546,12 @@ contract Carousel is VaultV2 { epochHasEnded(_id) { epochNull[_id] = true; - if(emissions[_id] > 0) { + if (emissions[_id] > 0) { emissionsToken.safeTransfer(treasury(), emissions[_id]); emissions[_id] = 0; } } - /** @notice sets emissions * @param _epochId epoch id * @param _emissionAmount emissions rate @@ -573,7 +582,11 @@ contract Carousel is VaultV2 { * @dev this function can only be called if there is no active deposit window * @param _addressesToDelist addresses to delist */ - function cleanUpRolloverQueue(address[] memory _addressesToDelist ) external onlyFactory epochHasStarted(epochs[epochs.length - 1]) { + function cleanUpRolloverQueue(address[] memory _addressesToDelist) + external + onlyFactory + epochHasStarted(epochs[epochs.length - 1]) + { // check that there is no active deposit window; for (uint256 i = 0; i < _addressesToDelist.length; i++) { address owner = _addressesToDelist[i]; @@ -582,11 +595,15 @@ contract Carousel is VaultV2 { uint256 queueIndex = index - 1; if (rolloverQueue[queueIndex].assets == 0) { // overwrite the item to be removed with the last item in the queue - rolloverQueue[queueIndex] = rolloverQueue[rolloverQueue.length - 1]; + rolloverQueue[queueIndex] = rolloverQueue[ + rolloverQueue.length - 1 + ]; // remove the last item in the queue rolloverQueue.pop(); // update the index of prev last user ( mapping index is allways array index + 1) - ownerToRollOverQueueIndex[rolloverQueue[queueIndex].receiver] = queueIndex + 1; + ownerToRollOverQueueIndex[rolloverQueue[queueIndex].receiver] = + queueIndex + + 1; // remove receiver from index mapping delete ownerToRollOverQueueIndex[owner]; } @@ -620,14 +637,13 @@ contract Carousel is VaultV2 { ); } - /** @notice returns the rollover index * @dev will revert if user is not in rollover queue * @param _owner address of the owner * @return rollover index */ function getRolloverIndex(address _owner) public view returns (uint256) { - return ownerToRollOverQueueIndex[_owner] - 1; + return ownerToRollOverQueueIndex[_owner] - 1; } /** @notice retruns deposit fee at this time @@ -635,7 +651,7 @@ contract Carousel is VaultV2 { * @param _assets amount of assets * @return feeAmount fee amount * @return _assetsAfterFee assets after fee - */ + */ function getEpochDepositFee(uint256 _id, uint256 _assets) public view @@ -664,7 +680,7 @@ contract Carousel is VaultV2 { entitledAmount = _assets.mulDivDown(emissions[_id], finalTVL[_id]); } - /** @notice returns the emissions to withdraw + /** @notice returns the emissions to withdraw * @param _id epoch id * @param _assets amount of shares * @return entitledShareAmount amount of emissions to withdraw @@ -674,15 +690,16 @@ contract Carousel is VaultV2 { view returns (uint256 entitledShareAmount) { - if(claimTVL[_id] != 0) { - entitledShareAmount = _assets.mulDivDown(finalTVL[_id], claimTVL[_id]); + if (claimTVL[_id] != 0) { + entitledShareAmount = _assets.mulDivDown( + finalTVL[_id], + claimTVL[_id] + ); } else { entitledShareAmount = 0; } - } - /** @notice returns the deposit queue length * @return queue length for the deposit */ @@ -750,7 +767,6 @@ contract Carousel is VaultV2 { epochId = rolloverQueue[index].epochId; } - /** @notice returns is user is enlisted in the rollover queue * @param _owner address of the user * @return bool is user enlisted in the rollover queue @@ -759,8 +775,8 @@ contract Carousel is VaultV2 { public view returns (bool) - { - if(ownerToRollOverQueueIndex[_owner] == 0) { + { + if (ownerToRollOverQueueIndex[_owner] == 0) { return false; } return rolloverQueue[getRolloverIndex(_owner)].assets != 0; @@ -887,5 +903,4 @@ contract Carousel is VaultV2 { uint256 assets, uint256 epochId ); - } diff --git a/src/v2/Carousel/CarouselFactory.sol b/src/v2/Carousel/CarouselFactory.sol index 2d48dfa8..ca53751e 100644 --- a/src/v2/Carousel/CarouselFactory.sol +++ b/src/v2/Carousel/CarouselFactory.sol @@ -54,12 +54,16 @@ contract CarouselFactory is VaultFactoryV2 { if (_marketCalldata.token == address(0)) revert AddressZero(); if (_marketCalldata.oracle == address(0)) revert AddressZero(); if (_marketCalldata.underlyingAsset == address(0)) revert AddressZero(); - - marketId = getMarketId(_marketCalldata.token, _marketCalldata.strike, _marketCalldata.underlyingAsset); - + + marketId = getMarketId( + _marketCalldata.token, + _marketCalldata.strike, + _marketCalldata.underlyingAsset + ); + if (marketIdToVaults[marketId][0] != address(0)) revert MarketAlreadyExists(); - + marketIdInfo[marketId] = MarketInfo( _marketCalldata.token, _marketCalldata.strike, @@ -68,7 +72,7 @@ contract CarouselFactory is VaultFactoryV2 { // set oracle for the market marketToOracle[marketId] = _marketCalldata.oracle; - + //y2kUSDC_99*PREMIUM premium = CarouselCreator.createCarousel( CarouselCreator.CarouselMarketConfiguration( @@ -127,14 +131,13 @@ contract CarouselFactory is VaultFactoryV2 { return (premium, collateral, marketId); } - - function createNewMarket(MarketConfigurationCalldata memory) - override + function createNewMarket(MarketConfigurationCalldata memory) external + override returns ( - address , - address , - uint256 + address, + address, + uint256 ) { revert(); @@ -186,11 +189,11 @@ contract CarouselFactory is VaultFactoryV2 { // to prevent the creation of epochs without emissions // this function is not used function createEpoch( - uint256 /*_marketId*/, - uint40 /*_epochBegin*/, - uint40 /*_epochEnd*/, + uint256, /*_marketId*/ + uint40, /*_epochBegin*/ + uint40, /*_epochEnd*/ uint16 /*_withdrawalFee*/ - ) override public returns (uint256, address[2] memory) { + ) public override returns (uint256, address[2] memory) { revert(); } @@ -214,8 +217,8 @@ contract CarouselFactory is VaultFactoryV2 { ICarousel premium = ICarousel(vaults[0]); ICarousel collat = ICarousel(vaults[1]); - if(premium.getDepositQueueLength() > 0) revert QueueNotEmpty(); - if(collat.getDepositQueueLength() > 0) revert QueueNotEmpty(); + if (premium.getDepositQueueLength() > 0) revert QueueNotEmpty(); + if (collat.getDepositQueueLength() > 0) revert QueueNotEmpty(); premium.changeRelayerFee(_relayerFee); collat.changeRelayerFee(_relayerFee); @@ -250,10 +253,9 @@ contract CarouselFactory is VaultFactoryV2 { public onlyTimeLocker { - ICarousel(_vault).cleanupRolloverQueue(_addresses); + ICarousel(_vault).cleanupRolloverQueue(_addresses); } - /*////////////////////////////////////////////////////////////// STRUCTS //////////////////////////////////////////////////////////////*/ diff --git a/src/v2/Controllers/ControllerPeggedAssetV2.sol b/src/v2/Controllers/ControllerPeggedAssetV2.sol index 5e948d98..88527f20 100644 --- a/src/v2/Controllers/ControllerPeggedAssetV2.sol +++ b/src/v2/Controllers/ControllerPeggedAssetV2.sol @@ -156,7 +156,7 @@ contract ControllerPeggedAssetV2 { collateralVault.epochExists(_epochId) == false ) revert EpochNotExist(); - if ( + if ( premiumVault.totalAssets(_epochId) == 0 || collateralVault.totalAssets(_epochId) == 0 ) { @@ -283,11 +283,12 @@ contract ControllerPeggedAssetV2 { , /*uint80 roundId*/ int256 answer, - uint256 startedAt, - /*uint256 updatedAt*/ /*uint80 answeredInRound*/ + uint256 startedAt, , - ) = sequencerUptimeFeed.latestRoundData(); + ) = /*uint256 updatedAt*/ + /*uint80 answeredInRound*/ + sequencerUptimeFeed.latestRoundData(); // Answer == 0: Sequencer is up // Answer == 1: Sequencer is down @@ -305,10 +306,16 @@ contract ControllerPeggedAssetV2 { AggregatorV3Interface priceFeed = AggregatorV3Interface( vaultFactory.marketToOracle(_marketId) ); - (uint80 roundID, int256 price, ,uint256 updatedAt, uint80 answeredInRound) = priceFeed - .latestRoundData(); + ( + uint80 roundID, + int256 price, + , + uint256 updatedAt, + uint80 answeredInRound + ) = priceFeed.latestRoundData(); - if (updatedAt < block.timestamp - MAX_UPDATE_TRESHOLD) revert PriceOutdated(); + if (updatedAt < block.timestamp - MAX_UPDATE_TRESHOLD) + revert PriceOutdated(); uint256 decimals = priceFeed.decimals(); diff --git a/src/v2/CustomERC1155/ERC1155.sol b/src/v2/CustomERC1155/ERC1155.sol index b07dee0e..59bef99e 100644 --- a/src/v2/CustomERC1155/ERC1155.sol +++ b/src/v2/CustomERC1155/ERC1155.sol @@ -39,7 +39,13 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { /** * @dev See {IERC165-supportsInterface}. */ - function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(ERC165, IERC165) + returns (bool) + { return interfaceId == type(IERC1155).interfaceId || interfaceId == type(IERC1155MetadataURI).interfaceId || @@ -67,8 +73,17 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { * * - `account` cannot be the zero address. */ - function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { - require(account != address(0), "ERC1155: address zero is not a valid owner"); + function balanceOf(address account, uint256 id) + public + view + virtual + override + returns (uint256) + { + require( + account != address(0), + "ERC1155: address zero is not a valid owner" + ); return _balances[id][account]; } @@ -86,7 +101,10 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { override returns (uint256[] memory) { - require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); + require( + accounts.length == ids.length, + "ERC1155: accounts and ids length mismatch" + ); uint256[] memory batchBalances = new uint256[](accounts.length); @@ -100,14 +118,24 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { /** * @dev See {IERC1155-setApprovalForAll}. */ - function setApprovalForAll(address operator, bool approved) public virtual override { + function setApprovalForAll(address operator, bool approved) + public + virtual + override + { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC1155-isApprovedForAll}. */ - function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { + function isApprovedForAll(address account, address operator) + public + view + virtual + override + returns (bool) + { return _operatorApprovals[account][operator]; } @@ -173,7 +201,10 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { _beforeTokenTransfer(operator, from, to, ids, amounts, data); uint256 fromBalance = _balances[id][from]; - require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); + require( + fromBalance >= amount, + "ERC1155: insufficient balance for transfer" + ); unchecked { _balances[id][from] = fromBalance - amount; } @@ -203,7 +234,10 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { uint256[] memory amounts, bytes memory data ) internal virtual { - require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + require( + ids.length == amounts.length, + "ERC1155: ids and amounts length mismatch" + ); require(to != address(0), "ERC1155: transfer to the zero address"); address operator = _msgSender(); @@ -215,7 +249,10 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { uint256 amount = amounts[i]; uint256 fromBalance = _balances[id][from]; - require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); + require( + fromBalance >= amount, + "ERC1155: insufficient balance for transfer" + ); unchecked { _balances[id][from] = fromBalance - amount; } @@ -226,7 +263,14 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { _afterTokenTransfer(operator, from, to, ids, amounts, data); - _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); + _doSafeBatchTransferAcceptanceCheck( + operator, + from, + to, + ids, + amounts, + data + ); } /** @@ -282,7 +326,7 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { _afterTokenTransfer(operator, address(0), to, ids, amounts, data); - // remove _doSafeTransferAcceptanceCheck to prevent reverting in queue + // remove _doSafeTransferAcceptanceCheck to prevent reverting in queue // if receiver is a contract and does not implement the ERC1155Holder interface funds will be stuck // _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); } @@ -305,7 +349,10 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { bytes memory data ) internal virtual { require(to != address(0), "ERC1155: mint to the zero address"); - require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + require( + ids.length == amounts.length, + "ERC1155: ids and amounts length mismatch" + ); address operator = _msgSender(); @@ -319,7 +366,14 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { _afterTokenTransfer(operator, address(0), to, ids, amounts, data); - _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); + _doSafeBatchTransferAcceptanceCheck( + operator, + address(0), + to, + ids, + amounts, + data + ); } /** @@ -371,7 +425,10 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { uint256[] memory amounts ) internal virtual { require(from != address(0), "ERC1155: burn from the zero address"); - require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + require( + ids.length == amounts.length, + "ERC1155: ids and amounts length mismatch" + ); address operator = _msgSender(); @@ -382,7 +439,10 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { uint256 amount = amounts[i]; uint256 fromBalance = _balances[id][from]; - require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); + require( + fromBalance >= amount, + "ERC1155: burn amount exceeds balance" + ); unchecked { _balances[id][from] = fromBalance - amount; } @@ -475,7 +535,15 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { bytes memory data ) private { if (to.isContract()) { - try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { + try + IERC1155Receiver(to).onERC1155Received( + operator, + from, + id, + amount, + data + ) + returns (bytes4 response) { if (response != IERC1155Receiver.onERC1155Received.selector) { revert("ERC1155: ERC1155Receiver rejected tokens"); } @@ -496,10 +564,18 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { bytes memory data ) private { if (to.isContract()) { - try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns ( - bytes4 response - ) { - if (response != IERC1155Receiver.onERC1155BatchReceived.selector) { + try + IERC1155Receiver(to).onERC1155BatchReceived( + operator, + from, + ids, + amounts, + data + ) + returns (bytes4 response) { + if ( + response != IERC1155Receiver.onERC1155BatchReceived.selector + ) { revert("ERC1155: ERC1155Receiver rejected tokens"); } } catch Error(string memory reason) { @@ -510,7 +586,11 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { } } - function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { + function _asSingletonArray(uint256 element) + private + pure + returns (uint256[] memory) + { uint256[] memory array = new uint256[](1); array[0] = element; diff --git a/src/v2/CustomERC1155/ERC1155Supply.sol b/src/v2/CustomERC1155/ERC1155Supply.sol index 2303c3c6..730927ad 100644 --- a/src/v2/CustomERC1155/ERC1155Supply.sol +++ b/src/v2/CustomERC1155/ERC1155Supply.sol @@ -54,7 +54,10 @@ abstract contract ERC1155Supply is ERC1155 { uint256 id = ids[i]; uint256 amount = amounts[i]; uint256 supply = _totalSupply[id]; - require(supply >= amount, "ERC1155: burn amount exceeds totalSupply"); + require( + supply >= amount, + "ERC1155: burn amount exceeds totalSupply" + ); unchecked { _totalSupply[id] = supply - amount; } diff --git a/src/v2/SemiFungibleVault.sol b/src/v2/SemiFungibleVault.sol index e21c615f..52df7005 100644 --- a/src/v2/SemiFungibleVault.sol +++ b/src/v2/SemiFungibleVault.sol @@ -5,9 +5,7 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { - ERC1155Supply -} from "./CustomERC1155/ERC1155Supply.sol"; +import {ERC1155Supply} from "./CustomERC1155/ERC1155Supply.sol"; import {ERC1155} from "./CustomERC1155/ERC1155.sol"; import {ISemiFungibleVault} from "./interfaces/ISemiFungibleVault.sol"; diff --git a/src/v2/TimeLock.sol b/src/v2/TimeLock.sol index 8a0eb4d1..ec7396ba 100644 --- a/src/v2/TimeLock.sol +++ b/src/v2/TimeLock.sol @@ -77,7 +77,7 @@ contract TimeLock { string calldata _func, bytes calldata _data, uint256 _timestamp - ) external payable onlyOwner returns (bytes memory) { + ) external payable onlyOwner returns (bytes memory) { bytes32 txId = getTxId(_target, _value, _func, _data, _timestamp); //check tx id queued @@ -109,7 +109,7 @@ contract TimeLock { data = _data; } - if(msg.value != _value) { + if (msg.value != _value) { revert ValueNotMatchError(msg.value, _value); } // call target diff --git a/src/v2/VaultFactoryV2.sol b/src/v2/VaultFactoryV2.sol index 059a12ef..157905d1 100644 --- a/src/v2/VaultFactoryV2.sol +++ b/src/v2/VaultFactoryV2.sol @@ -57,8 +57,8 @@ contract VaultFactoryV2 is Ownable { @return marketId uint256 of the marketId */ function createNewMarket(MarketConfigurationCalldata memory _marketCalldata) - virtual external + virtual onlyOwner returns ( address premium, @@ -69,7 +69,9 @@ contract VaultFactoryV2 is Ownable { return _createNewMarket(_marketCalldata); } - function _createNewMarket(MarketConfigurationCalldata memory _marketCalldata) + function _createNewMarket( + MarketConfigurationCalldata memory _marketCalldata + ) internal returns ( address premium, @@ -82,9 +84,11 @@ contract VaultFactoryV2 is Ownable { if (_marketCalldata.oracle == address(0)) revert AddressZero(); if (_marketCalldata.underlyingAsset == address(0)) revert AddressZero(); - - - marketId = getMarketId(_marketCalldata.token, _marketCalldata.strike, _marketCalldata.underlyingAsset); + marketId = getMarketId( + _marketCalldata.token, + _marketCalldata.strike, + _marketCalldata.underlyingAsset + ); marketIdInfo[marketId] = MarketInfo( _marketCalldata.token, _marketCalldata.strike, @@ -93,7 +97,7 @@ contract VaultFactoryV2 is Ownable { if (marketIdToVaults[marketId][0] != address(0)) revert MarketAlreadyExists(); - + // set oracle for the market marketToOracle[marketId] = _marketCalldata.oracle; @@ -147,7 +151,6 @@ contract VaultFactoryV2 is Ownable { return (premium, collateral, marketId); } - /** @notice Function set epoch for market, @param _marketId uint256 of the market index to create more assets in @@ -160,14 +163,13 @@ contract VaultFactoryV2 is Ownable { uint40 _epochBegin, uint40 _epochEnd, uint16 _withdrawalFee - ) virtual public onlyOwner returns (uint256 epochId, address[2] memory vaults) { - return - _createEpoch( - _marketId, - _epochBegin, - _epochEnd, - _withdrawalFee - ); + ) + public + virtual + onlyOwner + returns (uint256 epochId, address[2] memory vaults) + { + return _createEpoch(_marketId, _epochBegin, _epochEnd, _withdrawalFee); } function _createEpoch( @@ -203,6 +205,7 @@ contract VaultFactoryV2 is Ownable { ) ); } + /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ @@ -322,8 +325,9 @@ contract VaultFactoryV2 is Ownable { onlyTimeLocker { if (_oracle == address(0)) revert AddressZero(); - if(_marketId == 0) revert MarketDoesNotExist(_marketId); - if (marketToOracle[_marketId] == address(0)) revert MarketDoesNotExist(_marketId); + if (_marketId == 0) revert MarketDoesNotExist(_marketId); + if (marketToOracle[_marketId] == address(0)) + revert MarketDoesNotExist(_marketId); marketToOracle[_marketId] = _oracle; emit OracleChanged(_marketId, _oracle); @@ -384,15 +388,17 @@ contract VaultFactoryV2 is Ownable { @param _underlying Address of the underlying @return marketId uint256 of the marketId */ - function getMarketId(address _token, uint256 _strikePrice, address _underlying) - public - pure - returns (uint256 marketId) - { - return uint256(keccak256(abi.encodePacked(_token, _strikePrice, _underlying))); + function getMarketId( + address _token, + uint256 _strikePrice, + address _underlying + ) public pure returns (uint256 marketId) { + return + uint256( + keccak256(abi.encodePacked(_token, _strikePrice, _underlying)) + ); } - // get marketInfo function getMarketInfo(uint256 _marketId) public @@ -403,7 +409,7 @@ contract VaultFactoryV2 is Ownable { address underlyingAsset ) { - token = marketIdInfo[_marketId].token; + token = marketIdInfo[_marketId].token; strike = marketIdInfo[_marketId].strike; underlyingAsset = marketIdInfo[_marketId].underlyingAsset; } @@ -449,7 +455,6 @@ contract VaultFactoryV2 is Ownable { IVaultV2 collateral; } - struct MarketInfo { address token; uint256 strike; diff --git a/src/v2/VaultV2.sol b/src/v2/VaultV2.sol index 098365b9..c7bc355f 100644 --- a/src/v2/VaultV2.sol +++ b/src/v2/VaultV2.sol @@ -299,8 +299,11 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { if (_amount > finalTVL[_id]) revert AmountExceedsTVL(); if (epochAccounting[_id] + _amount > finalTVL[_id]) revert AmountExceedsTVL(); - if (!whitelistedAddresses[_receiver] && _receiver != counterPartyVault && _receiver != treasury()) - revert DestinationNotAuthorized(_receiver); + if ( + !whitelistedAddresses[_receiver] && + _receiver != counterPartyVault && + _receiver != treasury() + ) revert DestinationNotAuthorized(_receiver); epochAccounting[_id] += _amount; SemiFungibleVault.asset.safeTransfer(_receiver, _amount); } diff --git a/src/v2/interfaces/IVaultV2.sol b/src/v2/interfaces/IVaultV2.sol index 531394c5..ddd090bc 100644 --- a/src/v2/interfaces/IVaultV2.sol +++ b/src/v2/interfaces/IVaultV2.sol @@ -61,5 +61,4 @@ interface IVaultV2 { external view returns (bool); - } From 79c29c12f0846197309006722c5c99a638275ed3 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Fri, 28 Apr 2023 22:32:46 -0700 Subject: [PATCH 24/31] typo --- src/v2/Carousel/Carousel.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index cd588abd..65336d19 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -655,7 +655,7 @@ contract Carousel is VaultV2 { function getEpochDepositFee(uint256 _id, uint256 _assets) public view - returns (uint256 feeAmount, uint256 _assetsAfterFee) + returns (uint256 feeAmount, uint256 assetsAfterFee) { (uint256 maxX, , uint256 minX) = getEpochConfig(_id); // deposit fee is calcualted linearly between time of epoch creation and epoch starting (deposit window) @@ -664,7 +664,7 @@ contract Carousel is VaultV2 { // min minRequiredDeposit modifier ensures that _assets has high enough value to not devide by 0 // 0.5% = multiply by 10000 then divide by 50 feeAmount = _assets.mulDivDown(fee, 10000); - _assetsAfterFee = _assets - feeAmount; + assetsAfterFee = _assets - feeAmount; } /** @notice returns the emissions to withdraw From 11de4819e0f1f574a7decc50caa37ae8e063b519 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 1 May 2023 11:12:01 -0700 Subject: [PATCH 25/31] add direct admin change on timelocker --- src/v2/Carousel/Carousel.sol | 2 +- src/v2/TimeLock.sol | 8 +++++++ src/v2/VaultFactoryV2.sol | 2 +- src/v2/interfaces/IVaultFactoryV2.sol | 2 ++ test/V2/FactoryV2Test.t.sol | 32 ++++++++++++++++++++++++++- 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index 65336d19..29dc555c 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -650,7 +650,7 @@ contract Carousel is VaultV2 { * @param _id epoch id * @param _assets amount of assets * @return feeAmount fee amount - * @return _assetsAfterFee assets after fee + * @return assetsAfterFee assets after fee */ function getEpochDepositFee(uint256 _id, uint256 _assets) public diff --git a/src/v2/TimeLock.sol b/src/v2/TimeLock.sol index ec7396ba..b3360ccd 100644 --- a/src/v2/TimeLock.sol +++ b/src/v2/TimeLock.sol @@ -9,6 +9,7 @@ contract TimeLock { mapping(bytes32 => bool) public queued; address public policy; + address public factory; uint32 public constant MIN_DELAY = 7 days; uint32 public constant MAX_DELAY = 30 days; @@ -179,6 +180,13 @@ contract TimeLock { emit ChangeOwner(_newOwner); } + /** @notice change owner on factory + * @param _newOwner new owner + */ + function changeOwnerOnFactory(address _newOwner, address _factory) external onlyOwner { + IVaultFactoryV2(_factory).transferOwnership(_newOwner); + } + /*/////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ diff --git a/src/v2/VaultFactoryV2.sol b/src/v2/VaultFactoryV2.sol index 157905d1..67f83aee 100644 --- a/src/v2/VaultFactoryV2.sol +++ b/src/v2/VaultFactoryV2.sol @@ -337,7 +337,7 @@ contract VaultFactoryV2 is Ownable { @notice Timelocker function, changes owner address @param _owner Address of the new _owner */ - function changeOwner(address _owner) public onlyTimeLocker { + function transferOwnership(address _owner) public override onlyTimeLocker { if (_owner == address(0)) revert AddressZero(); _transferOwnership(_owner); } diff --git a/src/v2/interfaces/IVaultFactoryV2.sol b/src/v2/interfaces/IVaultFactoryV2.sol index 65819776..5c89d2a4 100644 --- a/src/v2/interfaces/IVaultFactoryV2.sol +++ b/src/v2/interfaces/IVaultFactoryV2.sol @@ -18,4 +18,6 @@ interface IVaultFactoryV2 { function getEpochFee(uint256) external view returns (uint16); function marketToOracle(uint256 _marketId) external view returns (address); + + function transferOwnership(address newOwner) external; } diff --git a/test/V2/FactoryV2Test.t.sol b/test/V2/FactoryV2Test.t.sol index 0642d73e..b2f761f0 100644 --- a/test/V2/FactoryV2Test.t.sol +++ b/test/V2/FactoryV2Test.t.sol @@ -9,10 +9,11 @@ import "../../src/v2/interfaces/IVaultV2.sol"; contract FactoryV2Test is Helper { VaultFactoryV2 factory; + TimeLock timelock; address controller; function setUp() public { - TimeLock timelock = new TimeLock(ADMIN); + timelock = new TimeLock(ADMIN); factory = new VaultFactoryV2( WETH, @@ -327,6 +328,35 @@ contract FactoryV2Test is Helper { assertEq(factory.marketToOracle(marketId), newOracle); } + function testTransferOwnership() public { + // test revert cases + vm.expectRevert(VaultFactoryV2.NotTimeLocker.selector); + factory.transferOwnership(address(0x20)); + + // imitate timelocker + vm.startPrank(address(factory.timelocker())); + vm.expectRevert(VaultFactoryV2.AddressZero.selector); + factory.transferOwnership(address(0)); + + // test success case + factory.transferOwnership(address(0x20)); + assertEq(factory.owner(), address(0x20)); + vm.stopPrank(); + + // interact through timelocker + vm.startPrank(address(0x222222)); + // test revert cases + vm.expectRevert(abi.encodeWithSelector(TimeLock.NotOwner.selector, address(0x222222))); + timelock.changeOwnerOnFactory(address(0x222222), address(factory)); + vm.stopPrank(); + + vm.startPrank(ADMIN); + // test success case + timelock.changeOwnerOnFactory(address(0x21), address(factory)); + assertEq(factory.owner(), address(0x21)); + vm.stopPrank(); + } + function createMarketHelper() public returns(uint256 marketId){ address token = address(0x1); From 5a7037faddc339e8ff17618b3b2388a875d7a83b Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 1 May 2023 11:14:26 -0700 Subject: [PATCH 26/31] prettier --- src/v2/Controllers/ControllerPeggedAssetV2.sol | 13 +++++-------- src/v2/TimeLock.sol | 9 ++++++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/v2/Controllers/ControllerPeggedAssetV2.sol b/src/v2/Controllers/ControllerPeggedAssetV2.sol index 88527f20..6de0c752 100644 --- a/src/v2/Controllers/ControllerPeggedAssetV2.sol +++ b/src/v2/Controllers/ControllerPeggedAssetV2.sol @@ -279,16 +279,13 @@ contract ControllerPeggedAssetV2 { * @return nowPrice Current token price */ function getLatestPrice(uint256 _marketId) public view returns (int256) { - ( - , - /*uint80 roundId*/ + ( + /*uint80 roundId*/, int256 answer, - uint256 startedAt, - , - - ) = /*uint256 updatedAt*/ + uint256 startedAt, + /*uint256 updatedAt*/, /*uint80 answeredInRound*/ - sequencerUptimeFeed.latestRoundData(); + ) = sequencerUptimeFeed.latestRoundData(); // Answer == 0: Sequencer is up // Answer == 1: Sequencer is down diff --git a/src/v2/TimeLock.sol b/src/v2/TimeLock.sol index b3360ccd..b5976604 100644 --- a/src/v2/TimeLock.sol +++ b/src/v2/TimeLock.sol @@ -181,9 +181,12 @@ contract TimeLock { } /** @notice change owner on factory - * @param _newOwner new owner - */ - function changeOwnerOnFactory(address _newOwner, address _factory) external onlyOwner { + * @param _newOwner new owner + */ + function changeOwnerOnFactory(address _newOwner, address _factory) + external + onlyOwner + { IVaultFactoryV2(_factory).transferOwnership(_newOwner); } From 16a18751e17777336a106ba243c0b9e344aabbf9 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 1 May 2023 17:22:38 -0700 Subject: [PATCH 27/31] refactor vault --- src/v2/Carousel/Carousel.sol | 132 ++++++++++++++++++++--------------- src/v2/VaultV2.sol | 50 +++++++------ 2 files changed, 98 insertions(+), 84 deletions(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index 29dc555c..3af79371 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -119,16 +119,16 @@ contract Carousel is VaultV2 { } /** - @notice Withdraw entitled deposited assets, checking if a depeg event - @param _id uint256 identifier of the epoch you want to withdraw from; - @param _assets uint256 of how many assets you want to withdraw, this value will be used to calculate how many assets you are entitle to according the vaults claimTVL; - @param _receiver Address of the receiver of the assets provided by this function, that represent the ownership of the transfered asset; - @param _owner Address of the owner of these said assets; - @return shares How many shares the owner is entitled to, according to the conditions; + @notice Withdraw entitled assets and burn shares of epoch + @param _id uint256 identifier of the epoch; + @param _shares uint256 amount of shares to withdraw, this value will be used to calculate how many assets you are entitle to according the vaults claimTVL; + @param _receiver Address of the receiver of the assets provided by this function, that represent the ownership of the transfered asset; + @param _owner Address of the _shares owner; + @return assets How many assets the owner is entitled to, according to the epoch outcome; */ function withdraw( uint256 _id, - uint256 _assets, + uint256 _shares, address _receiver, address _owner ) @@ -137,9 +137,9 @@ contract Carousel is VaultV2 { override(VaultV2) epochIdExists(_id) epochHasEnded(_id) - notRollingOver(_owner, _id, _assets) + notRollingOver(_owner, _id, _shares) nonReentrant - returns (uint256 shares) + returns (uint256 assets) { // make sure that epoch exists // epoch is resolved @@ -152,19 +152,18 @@ contract Carousel is VaultV2 { isApprovedForAll(_owner, msg.sender) == false ) revert OwnerDidNotAuthorize(msg.sender, _owner); - _burn(_owner, _id, _assets); - uint256 entitledShares; - uint256 entitledEmissions = previewEmissionsWithdraw(_id, _assets); + _burn(_owner, _id, _shares); + uint256 entitledEmissions = previewEmissionsWithdraw(_id, _shares); if (epochNull[_id] == false) { - entitledShares = previewWithdraw(_id, _assets); + assets = previewWithdraw(_id, _shares); } else { - entitledShares = _assets; + assets = _shares; } - if (entitledShares > 0) { - SemiFungibleVault.asset.safeTransfer(_receiver, entitledShares); + if (assets > 0) { + SemiFungibleVault.asset.safeTransfer(_receiver, assets); } if (entitledEmissions > 0) { - emissionsToken.safeTransfer(_receiver, entitledEmissions); + emissionsToken.safeTransfer(_receiver, assets); } emit WithdrawWithEmissions( @@ -172,12 +171,12 @@ contract Carousel is VaultV2 { _receiver, _owner, _id, - _assets, - entitledShares, + _shares, + assets, entitledEmissions ); - return entitledShares; + return assets; } /*/////////////////////////////////////////////////////////////// @@ -222,34 +221,34 @@ contract Carousel is VaultV2 { /** @notice enlists in rollover queue @dev user needs to have >= _assets in epoch (_epochId) @param _epochId epoch id - @param _assets uint256 of how many assets deposited; + @param _shares uint256 amount of shares to rollover; @param _receiver address of the receiver of the emissions; */ function enlistInRollover( uint256 _epochId, - uint256 _assets, + uint256 _shares, address _receiver - ) public epochIdExists(_epochId) minRequiredDeposit(_assets, _epochId) { + ) public epochIdExists(_epochId) minRequiredDeposit(_shares, _epochId) { // check if sender is approved by owner if ( msg.sender != _receiver && isApprovedForAll(_receiver, msg.sender) == false ) revert OwnerDidNotAuthorize(msg.sender, _receiver); // check if user has enough balance - if (balanceOf(_receiver, _epochId) < _assets) + if (balanceOf(_receiver, _epochId) < _shares) revert InsufficientBalance(); // check if user has already queued up a rollover if (isEnlistedInRolloverQueue(_receiver)) { uint256 index = getRolloverIndex(_receiver); // if so, update the queue - rolloverQueue[index].assets = _assets; + rolloverQueue[index].shares = _shares; rolloverQueue[index].epochId = _epochId; } else { // if not, add to queue rolloverQueue.push( QueueItem({ - assets: _assets, + shares: _shares, receiver: _receiver, epochId: _epochId }) @@ -258,7 +257,7 @@ contract Carousel is VaultV2 { ownerToRollOverQueueIndex[_receiver] = rolloverQueue.length; } - emit RolloverQueued(_receiver, _assets, _epochId); + emit RolloverQueued(_receiver, _shares, _epochId); } /** @notice delists from rollover queue @@ -280,7 +279,7 @@ contract Carousel is VaultV2 { // set assets to 0 but keep the queue item uint256 index = getRolloverIndex(_owner); - rolloverQueue[index].assets = 0; + rolloverQueue[index].shares = 0; rolloverQueue[index].epochId = 0; } @@ -315,7 +314,7 @@ contract Carousel is VaultV2 { // changing it to FIFO (first in first out) would require more code changes and would be more expensive // @note non neglectable min-deposit creates barriers for attackers to DDOS the queue - uint256 assetsToDeposit = queue[i].assets; + uint256 assetsToDeposit = queue[i].shares; if (depositFee > 0) { ( @@ -396,15 +395,15 @@ contract Carousel is VaultV2 { while ((index - prevIndex) < (_operations)) { // only roll over if last epoch is resolved and user rollover position is valid if ( - epochResolved[queue[index].epochId] && queue[index].assets > 0 + epochResolved[queue[index].epochId] && queue[index].shares > 0 ) { uint256 entitledAmount = previewWithdraw( queue[index].epochId, - queue[index].assets + queue[index].shares ); // mint only if user won epoch he is rolling over - if (entitledAmount > queue[index].assets) { + if (entitledAmount > queue[index].shares) { // @note previewAmountInShares can only be called if epoch is in profit uint256 relayerFeeInShares = previewAmountInShares( queue[index].epochId, @@ -412,7 +411,7 @@ contract Carousel is VaultV2 { ); // skip the rollover for the user if the assets cannot cover the relayer fee instead of revert. - if (queue[index].assets < relayerFeeInShares) { + if (queue[index].shares < relayerFeeInShares) { index++; continue; } @@ -420,10 +419,10 @@ contract Carousel is VaultV2 { // to calculate originalDepositValue get the diff between shares and value of shares // convert this value amount value back to shares // subtract from assets - uint256 originalDepositValue = queue[index].assets - + uint256 originalDepositValue = queue[index].shares - previewAmountInShares( queue[index].epochId, - (entitledAmount - queue[index].assets) + (entitledAmount - queue[index].shares) // subtract profit from share value ); // @note we know shares were locked up to this point _burn( @@ -452,16 +451,16 @@ contract Carousel is VaultV2 { originalDepositValue ) ); - uint256 assetsToMint = queue[index].assets - + uint256 amountToMint = queue[index].shares - relayerFeeInShares; - _mintShares(queue[index].receiver, _epochId, assetsToMint); + _mintShares(queue[index].receiver, _epochId, amountToMint); // amountToMint == shares emit Deposit( msg.sender, queue[index].receiver, _epochId, - assetsToMint + amountToMint ); - rolloverQueue[index].assets = assetsToMint; + rolloverQueue[index].shares = amountToMint; rolloverQueue[index].epochId = _epochId; // only pay relayer for successful mints executions++; @@ -510,7 +509,7 @@ contract Carousel is VaultV2 { emit Deposit(msg.sender, _receiver, _id, _assets); } else { depositQueue.push( - QueueItem({assets: _assets, receiver: _receiver, epochId: _id}) + QueueItem({shares: _assets, receiver: _receiver, epochId: _id}) ); emit DepositInQueue(msg.sender, _receiver, _id, _assets); @@ -593,7 +592,7 @@ contract Carousel is VaultV2 { uint256 index = ownerToRollOverQueueIndex[owner]; if (index == 0) continue; uint256 queueIndex = index - 1; - if (rolloverQueue[queueIndex].assets == 0) { + if (rolloverQueue[queueIndex].shares == 0) { // overwrite the item to be removed with the last item in the queue rolloverQueue[queueIndex] = rolloverQueue[ rolloverQueue.length - 1 @@ -717,53 +716,70 @@ contract Carousel is VaultV2 { /** @notice returns the total value locked in the rollover queue * @return tvl total value locked in the rollover queue */ - function getRolloverTVL(uint256 _epochId) + function getRolloverTVLByEpochId(uint256 _epochId) public view returns (uint256 tvl) { for (uint256 i = 0; i < rolloverQueue.length; i++) { + uint256 assets = previewWithdraw( + rolloverQueue[i].epochId, + rolloverQueue[i].shares + ); if ( rolloverQueue[i].epochId == _epochId && - (previewWithdraw( - rolloverQueue[i].epochId, - rolloverQueue[i].assets - ) > rolloverQueue[i].assets) + (assets > rolloverQueue[i].shares) // check if position is in profit and getting rollover ) { - tvl += rolloverQueue[i].assets; + tvl += assets; } } } + function getRolloverTVL() public + view + returns (uint256 tvl) { + for (uint256 i = 0; i < rolloverQueue.length; i++) { + uint256 assets = previewWithdraw( + rolloverQueue[i].epochId, + rolloverQueue[i].shares + ); + if ( + (assets > rolloverQueue[i].shares) // check if position is in profit and getting rollover + ) { + tvl += assets; + } + } + } + function getRolloverQueueItem(uint256 _index) public view returns ( address receiver, - uint256 assets, + uint256 shares, uint256 epochId ) { receiver = rolloverQueue[_index].receiver; - assets = rolloverQueue[_index].assets; + shares = rolloverQueue[_index].shares; epochId = rolloverQueue[_index].epochId; } /** @notice returns users rollover balance and epoch which is rolling over * @param _owner address of the user - * @return balance balance of the user + * @return shares balance of the user in rollover position * @return epochId epoch id */ function getRolloverPosition(address _owner) public view - returns (uint256 balance, uint256 epochId) + returns (uint256 shares, uint256 epochId) { if (!isEnlistedInRolloverQueue(_owner)) { return (0, 0); } uint256 index = getRolloverIndex(_owner); - balance = rolloverQueue[index].assets; + shares = rolloverQueue[index].shares; epochId = rolloverQueue[index].epochId; } @@ -779,7 +795,7 @@ contract Carousel is VaultV2 { if (ownerToRollOverQueueIndex[_owner] == 0) { return false; } - return rolloverQueue[getRolloverIndex(_owner)].assets != 0; + return rolloverQueue[getRolloverIndex(_owner)].shares != 0; } /** @notice returns the total value locked in the deposit queue @@ -787,7 +803,7 @@ contract Carousel is VaultV2 { */ function getDepositQueueTVL() public view returns (uint256 tvl) { for (uint256 i = 0; i < depositQueue.length; i++) { - tvl += depositQueue[i].assets; + tvl += depositQueue[i].shares; } } @@ -796,7 +812,7 @@ contract Carousel is VaultV2 { //////////////////////////////////////////////////////////////*/ struct QueueItem { - uint256 assets; + uint256 shares; address receiver; uint256 epochId; } @@ -831,18 +847,18 @@ contract Carousel is VaultV2 { /** @notice checks if not rolling over * @param _receiver address of the receiver * @param _epochId epoch id - * @param _assets amount of assets to deposit + * @param _shares amount of assets to deposit */ modifier notRollingOver( address _receiver, uint256 _epochId, - uint256 _assets + uint256 _shares ) { if (isEnlistedInRolloverQueue(_receiver)) { QueueItem memory item = rolloverQueue[getRolloverIndex(_receiver)]; if ( item.epochId == _epochId && - (balanceOf(_receiver, _epochId) - item.assets) < _assets + (balanceOf(_receiver, _epochId) - item.shares) < _shares ) revert AlreadyRollingOver(); } _; diff --git a/src/v2/VaultV2.sol b/src/v2/VaultV2.sol index c7bc355f..8084e874 100644 --- a/src/v2/VaultV2.sol +++ b/src/v2/VaultV2.sol @@ -81,9 +81,9 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { //////////////////////////////////////////////////////////////*/ /** - @param _id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000; - @param _assets uint256 representing how many assets the user wants to deposit, a fee will be taken from this value; - @param _receiver address of the receiver of the assets provided by this function, that represent the ownership of the deposited asset; + @param _id uint256 epoch identifier; + @param _assets uint256 amount of assets the user wants to deposit denominated in underlying asset decimals; + @param _receiver address of the receiver of the shares minted; */ function deposit( uint256 _id, @@ -112,7 +112,7 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { /** @notice Deposit ETH function @param _id uint256 representing the id of the epoch; - @param _receiver address of the receiver of the shares provided by this function, that represent the ownership of the deposited asset; + @param _receiver address of the receiver of the shares minted; */ function depositETH(uint256 _id, address _receiver) external @@ -133,16 +133,16 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { } /** - @notice Withdraw entitled deposited assets, checking if a depeg event - @param _id uint256 identifier of the epoch you want to withdraw from; - @param _assets uint256 of how many assets you want to withdraw, this value will be used to calculate how many assets you are entitle to according the vaults claimTVL; - @param _receiver Address of the receiver of the assets provided by this function, that represent the ownership of the transfered asset; - @param _owner Address of the owner of these said assets; - @return shares How many shares the owner is entitled to, according to the conditions; + @notice Withdraw entitled assets and burn shares of epoch + @param _id uint256 identifier of the epoch; + @param _shares uint256 amount of shares to withdraw, this value will be used to calculate how many assets you are entitle to according the vaults claimTVL; + @param _receiver Address of the receiver of the assets provided by this function, that represent the ownership of the transfered asset; + @param _owner Address of the _shares owner; + @return assets How many assets the owner is entitled to, according to the epoch outcome; */ function withdraw( uint256 _id, - uint256 _assets, + uint256 _shares, address _receiver, address _owner ) @@ -152,7 +152,7 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { epochIdExists(_id) epochHasEnded(_id) nonReentrant - returns (uint256 shares) + returns (uint256 assets) { if (_receiver == address(0)) revert AddressZero(); @@ -161,17 +161,15 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { isApprovedForAll(_owner, msg.sender) == false ) revert OwnerDidNotAuthorize(msg.sender, _owner); - _burn(_owner, _id, _assets); - - uint256 entitledShares; + _burn(_owner, _id, _shares); if (epochNull[_id] == false) { - entitledShares = previewWithdraw(_id, _assets); + assets = previewWithdraw(_id, _shares); } else { - entitledShares = _assets; + assets = _shares; } - if (entitledShares > 0) { - SemiFungibleVault.asset.safeTransfer(_receiver, entitledShares); + if (assets > 0) { + SemiFungibleVault.asset.safeTransfer(_receiver, assets); } emit Withdraw( @@ -179,11 +177,11 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { _receiver, _owner, _id, - _assets, - entitledShares + _shares, + assets ); - return entitledShares; + return assets; } /*/////////////////////////////////////////////////////////////// @@ -342,18 +340,18 @@ contract VaultV2 is IVaultV2, SemiFungibleVault, ReentrancyGuard { /** @notice Shows assets conversion output from withdrawing assets @param _id uint256 epoch identifier - @param _assets amount of user shares to withdraw + @param _shares amount of user shares to withdraw */ - function previewWithdraw(uint256 _id, uint256 _assets) + function previewWithdraw(uint256 _id, uint256 _shares) public view override(SemiFungibleVault) - returns (uint256 entitledAmount) + returns (uint256 entitledAssets) { // entitledAmount amount is derived from the claimTVL and the finalTVL // if user deposited 1000 assets and the claimTVL is 50% lower than finalTVL, the user is entitled to 500 assets // if user deposited 1000 assets and the claimTVL is 50% higher than finalTVL, the user is entitled to 1500 assets - entitledAmount = _assets.mulDivDown(claimTVL[_id], finalTVL[_id]); + entitledAssets = _shares.mulDivDown(claimTVL[_id], finalTVL[_id]); } /** @notice Lookup total epochs length From 5cb2890e9826b06fff95014cf8b016b4f441dd27 Mon Sep 17 00:00:00 2001 From: 3xHarry Date: Mon, 1 May 2023 20:07:46 -0700 Subject: [PATCH 28/31] fix test --- src/v2/Carousel/Carousel.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v2/Carousel/Carousel.sol b/src/v2/Carousel/Carousel.sol index 3af79371..b56da25e 100644 --- a/src/v2/Carousel/Carousel.sol +++ b/src/v2/Carousel/Carousel.sol @@ -163,7 +163,7 @@ contract Carousel is VaultV2 { SemiFungibleVault.asset.safeTransfer(_receiver, assets); } if (entitledEmissions > 0) { - emissionsToken.safeTransfer(_receiver, assets); + emissionsToken.safeTransfer(_receiver, entitledEmissions); } emit WithdrawWithEmissions( From 17dbca9e833d90427542c6793a7975bbacfbb300 Mon Sep 17 00:00:00 2001 From: y2kdev Date: Mon, 8 May 2023 12:13:14 -0400 Subject: [PATCH 29/31] update dependencies --- test/legacy_v1/Controller.sol | 347 ---------- test/legacy_v1/ControllerHelper.sol | 12 +- test/legacy_v1/ControllerTest.t.sol | 12 +- test/legacy_v1/LockTest.t.sol | 2 +- test/legacy_v1/OracleHelper.sol | 12 +- test/legacy_v1/OracleTest.t.sol | 12 +- test/legacy_v1/OwnerHelper.sol | 10 +- test/legacy_v1/OwnerTest.t.sol | 10 +- test/legacy_v1/RewardsBalanceHelper.sol | 10 +- test/legacy_v1/RewardsBalanceTest.t.sol | 10 +- test/legacy_v1/RewardsFactoryHelper.sol | 8 +- test/legacy_v1/RewardsFactoryTest.t.sol | 12 +- test/legacy_v1/SemiFungibleVault.sol | 146 ---- test/legacy_v1/Vault.sol | 382 ---------- test/legacy_v1/VaultFactory.sol | 654 ------------------ test/legacy_v1/VaultFactoryHelper.sol | 8 +- test/legacy_v1/VaultFactoryTest.t.sol | 8 +- test/legacy_v1/VaultHelper.sol | 8 +- test/legacy_v1/VaultTest.t.sol | 8 +- test/legacy_v1/interfaces/IController.sol | 12 - test/legacy_v1/interfaces/IKeeper.sol | 16 - test/legacy_v1/interfaces/IStakingRewards.sol | 26 - test/legacy_v1/interfaces/IVault.sol | 173 ----- test/legacy_v1/interfaces/IVaultFactory.sol | 221 ------ test/legacy_v1/interfaces/IWETH.sol | 10 - test/legacy_v1/rewards/IStakingRewards.sol | 26 - test/legacy_v1/rewards/Owned.sol | 47 -- .../rewards/PausableRewardsFactory.sol | 106 --- .../rewards/PausableStakingRewards.sol | 244 ------- test/legacy_v1/rewards/RewardBalances.sol | 56 -- .../rewards/RewardsDistributionRecipient.sol | 26 - test/legacy_v1/rewards/RewardsFactory.sol | 106 --- test/legacy_v1/rewards/StakingRewards.sol | 243 ------- yarn.lock | 580 ++++++++++++++++ 34 files changed, 651 insertions(+), 2912 deletions(-) delete mode 100644 test/legacy_v1/Controller.sol delete mode 100644 test/legacy_v1/SemiFungibleVault.sol delete mode 100644 test/legacy_v1/Vault.sol delete mode 100644 test/legacy_v1/VaultFactory.sol delete mode 100644 test/legacy_v1/interfaces/IController.sol delete mode 100644 test/legacy_v1/interfaces/IKeeper.sol delete mode 100644 test/legacy_v1/interfaces/IStakingRewards.sol delete mode 100644 test/legacy_v1/interfaces/IVault.sol delete mode 100644 test/legacy_v1/interfaces/IVaultFactory.sol delete mode 100644 test/legacy_v1/interfaces/IWETH.sol delete mode 100644 test/legacy_v1/rewards/IStakingRewards.sol delete mode 100644 test/legacy_v1/rewards/Owned.sol delete mode 100644 test/legacy_v1/rewards/PausableRewardsFactory.sol delete mode 100644 test/legacy_v1/rewards/PausableStakingRewards.sol delete mode 100644 test/legacy_v1/rewards/RewardBalances.sol delete mode 100644 test/legacy_v1/rewards/RewardsDistributionRecipient.sol delete mode 100644 test/legacy_v1/rewards/RewardsFactory.sol delete mode 100644 test/legacy_v1/rewards/StakingRewards.sol create mode 100644 yarn.lock diff --git a/test/legacy_v1/Controller.sol b/test/legacy_v1/Controller.sol deleted file mode 100644 index 04c92d99..00000000 --- a/test/legacy_v1/Controller.sol +++ /dev/null @@ -1,347 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import {ERC20} from "@solmate/tokens/ERC20.sol"; -import "./Vault.sol"; -import "./VaultFactory.sol"; -import "@chainlink/interfaces/AggregatorV3Interface.sol"; -import "@chainlink/interfaces/AggregatorV2V3Interface.sol"; - -/// @author MiguelBits - -contract Controller { - VaultFactory public immutable vaultFactory; - AggregatorV2V3Interface internal sequencerUptimeFeed; - - uint256 private constant GRACE_PERIOD_TIME = 3600; - - /*////////////////////////////////////////////////////////////// - ERRORS - //////////////////////////////////////////////////////////////*/ - - error MarketDoesNotExist(uint256 marketId); - error SequencerDown(); - error GracePeriodNotOver(); - error ZeroAddress(); - error EpochFinishedAlready(); - error PriceNotAtStrikePrice(int256 price); - error EpochNotStarted(); - error EpochExpired(); - error OraclePriceZero(); - error RoundIDOutdated(); - error EpochNotExist(); - error EpochNotExpired(); - error VaultNotZeroTVL(); - - /*////////////////////////////////////////////////////////////// - EVENTS - //////////////////////////////////////////////////////////////*/ - - /** @notice Depegs insurance vault when event is emitted - * @param epochMarketID Current market epoch ID - * @param tvl Current TVL - * @param isDisaster Flag if event isDisaster - * @param epoch Current epoch - * @param time Current time - * @param depegPrice Price that triggered depeg - */ - event DepegInsurance( - bytes32 epochMarketID, - VaultTVL tvl, - bool isDisaster, - uint256 epoch, - uint256 time, - int256 depegPrice - ); - - event NullEpoch( - bytes32 epochMarketID, - VaultTVL tvl, - uint256 epoch, - uint256 time - ); - - struct VaultTVL { - uint256 RISK_claimTVL; - uint256 RISK_finalTVL; - uint256 INSR_claimTVL; - uint256 INSR_finalTVL; - } - - /*////////////////////////////////////////////////////////////// - CONSTRUCTOR - //////////////////////////////////////////////////////////////*/ - - /** @notice Contract constructor - * @param _factory VaultFactory address - * @param _l2Sequencer Arbitrum sequencer address - */ - constructor(address _factory, address _l2Sequencer) { - if (_factory == address(0)) revert ZeroAddress(); - - if (_l2Sequencer == address(0)) revert ZeroAddress(); - - vaultFactory = VaultFactory(_factory); - sequencerUptimeFeed = AggregatorV2V3Interface(_l2Sequencer); - } - - /*////////////////////////////////////////////////////////////// - FUNCTIONS - //////////////////////////////////////////////////////////////*/ - - /** @notice Trigger depeg event - * @param marketIndex Target market index - * @param epochEnd End of epoch set for market - */ - function triggerDepeg(uint256 marketIndex, uint256 epochEnd) public { - address[] memory vaultsAddress = vaultFactory.getVaults(marketIndex); - Vault insrVault = Vault(vaultsAddress[0]); - Vault riskVault = Vault(vaultsAddress[1]); - - if (vaultsAddress[0] == address(0) || vaultsAddress[1] == address(0)) - revert MarketDoesNotExist(marketIndex); - - if (insrVault.idExists(epochEnd) == false) revert EpochNotExist(); - - if (insrVault.strikePrice() <= getLatestPrice(insrVault.tokenInsured())) - revert PriceNotAtStrikePrice( - getLatestPrice(insrVault.tokenInsured()) - ); - - if (insrVault.idEpochBegin(epochEnd) > block.timestamp) - revert EpochNotStarted(); - - if (block.timestamp > epochEnd) revert EpochExpired(); - - //require this function cannot be called twice in the same epoch for the same vault - if (insrVault.idEpochEnded(epochEnd)) revert EpochFinishedAlready(); - if (riskVault.idEpochEnded(epochEnd)) revert EpochFinishedAlready(); - - insrVault.endEpoch(epochEnd); - riskVault.endEpoch(epochEnd); - - insrVault.setClaimTVL(epochEnd, riskVault.idFinalTVL(epochEnd)); - riskVault.setClaimTVL(epochEnd, insrVault.idFinalTVL(epochEnd)); - - insrVault.sendTokens(epochEnd, address(riskVault)); - riskVault.sendTokens(epochEnd, address(insrVault)); - - VaultTVL memory tvl = VaultTVL( - riskVault.idClaimTVL(epochEnd), - riskVault.idFinalTVL(epochEnd), - insrVault.idClaimTVL(epochEnd), - insrVault.idFinalTVL(epochEnd) - ); - - AggregatorV3Interface priceFeed = AggregatorV3Interface( - vaultFactory.tokenToOracle(insrVault.tokenInsured()) - ); - (, int256 price, , , ) = priceFeed.latestRoundData(); - - emit DepegInsurance( - keccak256( - abi.encodePacked( - marketIndex, - insrVault.idEpochBegin(epochEnd), - epochEnd - ) - ), - tvl, - true, - epochEnd, - block.timestamp, - price - ); - } - - /** @notice Trigger epoch end without depeg event - * @param marketIndex Target market index - * @param epochEnd End of epoch set for market - */ - function triggerEndEpoch(uint256 marketIndex, uint256 epochEnd) public { - if (block.timestamp <= epochEnd) revert EpochNotExpired(); - - address[] memory vaultsAddress = vaultFactory.getVaults(marketIndex); - - Vault insrVault = Vault(vaultsAddress[0]); - Vault riskVault = Vault(vaultsAddress[1]); - - if (vaultsAddress[0] == address(0) || vaultsAddress[1] == address(0)) - revert MarketDoesNotExist(marketIndex); - - if ( - insrVault.idExists(epochEnd) == false || - riskVault.idExists(epochEnd) == false - ) revert EpochNotExist(); - - //require this function cannot be called twice in the same epoch for the same vault - if (insrVault.idEpochEnded(epochEnd)) revert EpochFinishedAlready(); - if (riskVault.idEpochEnded(epochEnd)) revert EpochFinishedAlready(); - - insrVault.endEpoch(epochEnd); - riskVault.endEpoch(epochEnd); - - insrVault.setClaimTVL(epochEnd, 0); - riskVault.setClaimTVL( - epochEnd, - insrVault.idFinalTVL(epochEnd) + riskVault.idFinalTVL(epochEnd) - ); - insrVault.sendTokens(epochEnd, address(riskVault)); - - VaultTVL memory tvl = VaultTVL( - riskVault.idClaimTVL(epochEnd), - riskVault.idFinalTVL(epochEnd), - insrVault.idClaimTVL(epochEnd), - insrVault.idFinalTVL(epochEnd) - ); - - emit DepegInsurance( - keccak256( - abi.encodePacked( - marketIndex, - insrVault.idEpochBegin(epochEnd), - epochEnd - ) - ), - tvl, - false, - epochEnd, - block.timestamp, - getLatestPrice(insrVault.tokenInsured()) - ); - } - - /** @notice Trigger epoch invalid when one vault has 0 TVL - * @param marketIndex Target market index - * @param epochEnd End of epoch set for market - */ - function triggerNullEpoch(uint256 marketIndex, uint256 epochEnd) public { - address[] memory vaultsAddress = vaultFactory.getVaults(marketIndex); - - Vault insrVault = Vault(vaultsAddress[0]); - Vault riskVault = Vault(vaultsAddress[1]); - - if (vaultsAddress[0] == address(0) || vaultsAddress[1] == address(0)) - revert MarketDoesNotExist(marketIndex); - - if ( - insrVault.idExists(epochEnd) == false || - riskVault.idExists(epochEnd) == false - ) revert EpochNotExist(); - - if (block.timestamp < insrVault.idEpochBegin(epochEnd)) - revert EpochNotStarted(); - - if ( - insrVault.idExists(epochEnd) == false || - riskVault.idExists(epochEnd) == false - ) revert EpochNotExist(); - - //require this function cannot be called twice in the same epoch for the same vault - if (insrVault.idEpochEnded(epochEnd)) revert EpochFinishedAlready(); - if (riskVault.idEpochEnded(epochEnd)) revert EpochFinishedAlready(); - - //set claim TVL to 0 if total assets are 0 - if (insrVault.totalAssets(epochEnd) == 0) { - insrVault.endEpoch(epochEnd); - riskVault.endEpoch(epochEnd); - - insrVault.setClaimTVL(epochEnd, 0); - riskVault.setClaimTVL(epochEnd, riskVault.idFinalTVL(epochEnd)); - - riskVault.setEpochNull(epochEnd); - } else if (riskVault.totalAssets(epochEnd) == 0) { - insrVault.endEpoch(epochEnd); - riskVault.endEpoch(epochEnd); - - insrVault.setClaimTVL(epochEnd, insrVault.idFinalTVL(epochEnd)); - riskVault.setClaimTVL(epochEnd, 0); - - insrVault.setEpochNull(epochEnd); - } else revert VaultNotZeroTVL(); - - VaultTVL memory tvl = VaultTVL( - riskVault.idClaimTVL(epochEnd), - riskVault.idFinalTVL(epochEnd), - insrVault.idClaimTVL(epochEnd), - insrVault.idFinalTVL(epochEnd) - ); - - emit NullEpoch( - keccak256( - abi.encodePacked( - marketIndex, - insrVault.idEpochBegin(epochEnd), - epochEnd - ) - ), - tvl, - epochEnd, - block.timestamp - ); - } - - /*////////////////////////////////////////////////////////////// - GETTERS - //////////////////////////////////////////////////////////////*/ - /** @notice Lookup token price - * @param _token Target token address - * @return nowPrice Current token price - */ - function getLatestPrice(address _token) - public - view - returns (int256 nowPrice) - { - ( - , - /*uint80 roundId*/ - int256 answer, - uint256 startedAt, /*uint256 updatedAt*/ /*uint80 answeredInRound*/ - , - - ) = sequencerUptimeFeed.latestRoundData(); - - // Answer == 0: Sequencer is up - // Answer == 1: Sequencer is down - bool isSequencerUp = answer == 0; - if (!isSequencerUp) { - revert SequencerDown(); - } - - // Make sure the grace period has passed after the sequencer is back up. - uint256 timeSinceUp = block.timestamp - startedAt; - if (timeSinceUp <= GRACE_PERIOD_TIME) { - revert GracePeriodNotOver(); - } - - AggregatorV3Interface priceFeed = AggregatorV3Interface( - vaultFactory.tokenToOracle(_token) - ); - (uint80 roundID, int256 price, , , uint80 answeredInRound) = priceFeed - .latestRoundData(); - - if (priceFeed.decimals() < 18) { - uint256 decimals = 10**(18 - (priceFeed.decimals())); - price = price * int256(decimals); - } else if (priceFeed.decimals() == 18) { - price = price; - } else { - uint256 decimals = 10**((priceFeed.decimals() - 18)); - price = price / int256(decimals); - } - - if (price <= 0) revert OraclePriceZero(); - - if (answeredInRound < roundID) revert RoundIDOutdated(); - - return price; - } - - /** @notice Lookup target VaultFactory address - * @dev need to find way to express typecasts in NatSpec - */ - function getVaultFactory() external view returns (address) { - return address(vaultFactory); - } -} diff --git a/test/legacy_v1/ControllerHelper.sol b/test/legacy_v1/ControllerHelper.sol index c97701b0..78f73090 100644 --- a/test/legacy_v1/ControllerHelper.sol +++ b/test/legacy_v1/ControllerHelper.sol @@ -2,13 +2,13 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory, TimeLock} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; -import {PegOracle} from "../src/oracles/PegOracle.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory, TimeLock} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; +import {PegOracle} from "../../src/oracles/PegOracle.sol"; import {ERC20} from "@solmate/tokens/ERC20.sol"; -import {FakeOracle} from "./oracles/FakeOracle.sol"; -import {DepegOracle} from "./oracles/DepegOracle.sol"; +import {FakeOracle} from "../oracles/FakeOracle.sol"; +import {DepegOracle} from "../oracles/DepegOracle.sol"; /// @author nexusflip diff --git a/test/legacy_v1/ControllerTest.t.sol b/test/legacy_v1/ControllerTest.t.sol index f9c921d4..cbc06332 100644 --- a/test/legacy_v1/ControllerTest.t.sol +++ b/test/legacy_v1/ControllerTest.t.sol @@ -2,14 +2,14 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; -import {PegOracle} from "../src/oracles/PegOracle.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; +import {PegOracle} from "../../src/oracles/PegOracle.sol"; import {ERC20} from "@solmate/tokens/ERC20.sol"; import {ControllerHelper} from "./ControllerHelper.sol"; -import {FakeOracle} from "./oracles/FakeOracle.sol"; -import {DepegOracle} from "./oracles/DepegOracle.sol"; +import {FakeOracle} from "../oracles/FakeOracle.sol"; +import {DepegOracle} from "../oracles/DepegOracle.sol"; /// @author nexusflip /// @author MiguelBits diff --git a/test/legacy_v1/LockTest.t.sol b/test/legacy_v1/LockTest.t.sol index 23d351d1..e414637b 100644 --- a/test/legacy_v1/LockTest.t.sol +++ b/test/legacy_v1/LockTest.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {LockRewards} from "../src/lock-rewards/LockRewards.sol"; +import {LockRewards} from "../../src/lock-rewards/LockRewards.sol"; import {ERC20} from "@solmate/tokens/ERC20.sol"; /// @author MiguelBits diff --git a/test/legacy_v1/OracleHelper.sol b/test/legacy_v1/OracleHelper.sol index f89f7bc7..fc05f828 100644 --- a/test/legacy_v1/OracleHelper.sol +++ b/test/legacy_v1/OracleHelper.sol @@ -2,12 +2,12 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory, TimeLock} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; -import {PegOracle} from "../src/oracles/PegOracle.sol"; -import {FakeOracle} from "./oracles/FakeOracle.sol"; -import {FakeFakeOracle} from "./oracles/FakeFakeOracle.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory, TimeLock} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; +import {PegOracle} from "../../src/oracles/PegOracle.sol"; +import {FakeOracle} from "../oracles/FakeOracle.sol"; +import {FakeFakeOracle} from "../oracles/FakeFakeOracle.sol"; import "@chainlink/interfaces/AggregatorV3Interface.sol"; /// @author nexusflip diff --git a/test/legacy_v1/OracleTest.t.sol b/test/legacy_v1/OracleTest.t.sol index c7c704c7..7da228a0 100644 --- a/test/legacy_v1/OracleTest.t.sol +++ b/test/legacy_v1/OracleTest.t.sol @@ -2,14 +2,14 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory, TimeLock} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory, TimeLock} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; import {OracleHelper} from "./OracleHelper.sol"; -import {FakeOracle} from "./oracles/FakeOracle.sol"; +import {FakeOracle} from "../oracles/FakeOracle.sol"; import {ERC20} from "@solmate/tokens/ERC20.sol"; -import {PegOracle} from "../src/oracles/PegOracle.sol"; -import {FakeFakeOracle} from "../test/oracles/FakeFakeOracle.sol"; +import {PegOracle} from "../../src/oracles/PegOracle.sol"; +import {FakeFakeOracle} from "../oracles/FakeFakeOracle.sol"; import "@chainlink/interfaces/AggregatorV3Interface.sol"; /// @author nexusflip diff --git a/test/legacy_v1/OwnerHelper.sol b/test/legacy_v1/OwnerHelper.sol index 4a830b21..06ae2efb 100644 --- a/test/legacy_v1/OwnerHelper.sol +++ b/test/legacy_v1/OwnerHelper.sol @@ -2,11 +2,11 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory, TimeLock} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; -import {FakeOracle} from "./oracles/FakeOracle.sol"; -import {Owned} from "../src/rewards/Owned.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory, TimeLock} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; +import {FakeOracle} from "../oracles/FakeOracle.sol"; +import {Owned} from "../../src/legacy_v1/rewards/Owned.sol"; /// @author nexusflip diff --git a/test/legacy_v1/OwnerTest.t.sol b/test/legacy_v1/OwnerTest.t.sol index dfd56114..90961653 100644 --- a/test/legacy_v1/OwnerTest.t.sol +++ b/test/legacy_v1/OwnerTest.t.sol @@ -2,13 +2,13 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; import {OwnerHelper} from "./OwnerHelper.sol"; -import {FakeOracle} from "./oracles/FakeOracle.sol"; +import {FakeOracle} from "../oracles/FakeOracle.sol"; import {ERC20} from "@solmate/tokens/ERC20.sol"; -import {Owned} from "../src/rewards/Owned.sol"; +import {Owned} from "../../src/legacy_v1/rewards/Owned.sol"; /// @author nexusflip /// @author MiguelBits diff --git a/test/legacy_v1/RewardsBalanceHelper.sol b/test/legacy_v1/RewardsBalanceHelper.sol index 094a8a54..04a4098e 100644 --- a/test/legacy_v1/RewardsBalanceHelper.sol +++ b/test/legacy_v1/RewardsBalanceHelper.sol @@ -2,11 +2,11 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory, TimeLock} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; -import {RewardsFactory} from "../src/rewards/RewardsFactory.sol"; -import {RewardBalances} from "../src/rewards/RewardBalances.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory, TimeLock} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; +import {RewardsFactory} from "../../src/legacy_v1/rewards/RewardsFactory.sol"; +import {RewardBalances} from "../../src/legacy_v1/rewards/RewardBalances.sol"; import {GovToken} from "./GovToken.sol"; /// @author nexusflip diff --git a/test/legacy_v1/RewardsBalanceTest.t.sol b/test/legacy_v1/RewardsBalanceTest.t.sol index ff8bdbc1..f1b19665 100644 --- a/test/legacy_v1/RewardsBalanceTest.t.sol +++ b/test/legacy_v1/RewardsBalanceTest.t.sol @@ -2,12 +2,12 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory, TimeLock} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; -import {StakingRewards} from "../src/rewards/StakingRewards.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory, TimeLock} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; +import {StakingRewards} from "../../src/legacy_v1/rewards/StakingRewards.sol"; import {RewardsBalanceHelper} from "./RewardsBalanceHelper.sol"; -import {RewardBalances} from "../src/rewards/RewardBalances.sol"; +import {RewardBalances} from "../../src/legacy_v1/rewards/RewardBalances.sol"; import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; /// @author nexusflip diff --git a/test/legacy_v1/RewardsFactoryHelper.sol b/test/legacy_v1/RewardsFactoryHelper.sol index e6f4a041..8dfe86c7 100644 --- a/test/legacy_v1/RewardsFactoryHelper.sol +++ b/test/legacy_v1/RewardsFactoryHelper.sol @@ -2,10 +2,10 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory, TimeLock} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; -import {RewardsFactory} from "../src/rewards/RewardsFactory.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory, TimeLock} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; +import {RewardsFactory} from "../../src/legacy_v1/rewards/RewardsFactory.sol"; import {GovToken} from "./GovToken.sol"; /// @author nexusflip diff --git a/test/legacy_v1/RewardsFactoryTest.t.sol b/test/legacy_v1/RewardsFactoryTest.t.sol index 7b335145..a77bc07b 100644 --- a/test/legacy_v1/RewardsFactoryTest.t.sol +++ b/test/legacy_v1/RewardsFactoryTest.t.sol @@ -2,13 +2,13 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; -import {RewardsFactory} from "../src/rewards/RewardsFactory.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; +import {RewardsFactory} from "../../src/legacy_v1/rewards/RewardsFactory.sol"; import {RewardsFactoryHelper} from "./RewardsFactoryHelper.sol"; -import {FakeOracle} from "./oracles/FakeOracle.sol"; -import {StakingRewards} from "../src/rewards/StakingRewards.sol"; +import {FakeOracle} from "../oracles/FakeOracle.sol"; +import {StakingRewards} from "../../src/legacy_v1/rewards/StakingRewards.sol"; /// @author nexusflip diff --git a/test/legacy_v1/SemiFungibleVault.sol b/test/legacy_v1/SemiFungibleVault.sol deleted file mode 100644 index 27514292..00000000 --- a/test/legacy_v1/SemiFungibleVault.sol +++ /dev/null @@ -1,146 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import {ERC20} from "@solmate/tokens/ERC20.sol"; -import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol"; -import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol"; -import { - ERC1155Supply -} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol"; -import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; - -/// @author MiguelBits -/// @author SlumDog - -abstract contract SemiFungibleVault is ERC1155Supply { - using SafeTransferLib for ERC20; - using FixedPointMathLib for uint256; - - /*/////////////////////////////////////////////////////////////// - IMMUTABLES AND STORAGE - //////////////////////////////////////////////////////////////*/ - ERC20 public immutable asset; - string public name; - string public symbol; - bytes internal constant EMPTY = ""; - - /*/////////////////////////////////////////////////////////////// - EVENTS - //////////////////////////////////////////////////////////////*/ - - /** @notice Deposit into vault when event is emitted - * @param caller Address of deposit caller - * @param owner receiver who will own of the tokens representing this deposit - * @param id Vault id - * @param assets Amount of owner assets to deposit into vault - */ - event Deposit( - address caller, - address indexed owner, - uint256 indexed id, - uint256 assets - ); - - /** @notice Withdraw from vault when event is emitted - * @param caller Address of withdraw caller - * @param receiver Address of receiver of assets - * @param owner Owner of shares - * @param id Vault id - * @param assets Amount of owner assets to withdraw from vault - * @param shares Amount of owner shares to burn - */ - event Withdraw( - address caller, - address receiver, - address indexed owner, - uint256 indexed id, - uint256 assets, - uint256 shares - ); - - /** @notice Contract constructor - * @param _asset ERC20 token - * @param _name Token name - * @param _symbol Token symbol - */ - constructor( - ERC20 _asset, - string memory _name, - string memory _symbol - ) ERC1155("") { - asset = _asset; - name = _name; - symbol = _symbol; - } - - /*/////////////////////////////////////////////////////////////// - DEPOSIT/WITHDRAWAL LOGIC - //////////////////////////////////////////////////////////////*/ - - /** @notice Triggers deposit into vault and mints shares for receiver - * @param id Vault id - * @param assets Amount of tokens to deposit - * @param receiver Receiver of shares - */ - function deposit( - uint256 id, - uint256 assets, - address receiver - ) public virtual { - // Need to transfer before minting or ERC777s could reenter. - asset.safeTransferFrom(msg.sender, address(this), assets); - - _mint(receiver, id, assets, EMPTY); - - emit Deposit(msg.sender, receiver, id, assets); - } - - /** @notice Triggers withdraw from vault and burns receivers' shares - * @param id Vault id - * @param assets Amount of tokens to withdraw - * @param receiver Receiver of assets - * @param owner Owner of shares - * @return shares Amount of shares burned - */ - function withdraw( - uint256 id, - uint256 assets, - address receiver, - address owner - ) external virtual returns (uint256 shares) { - require( - msg.sender == owner || isApprovedForAll(owner, msg.sender), - "Only owner can withdraw, or owner has approved receiver for all" - ); - - shares = previewWithdraw(id, assets); - - _burn(owner, id, shares); - - emit Withdraw(msg.sender, receiver, owner, id, assets, shares); - asset.safeTransfer(receiver, assets); - } - - /*/////////////////////////////////////////////////////////////// - ACCOUNTING LOGIC - //////////////////////////////////////////////////////////////*/ - - /**@notice Returns total assets for token - * @param _id uint256 token id of token - */ - function totalAssets(uint256 _id) public view virtual returns (uint256) { - return totalSupply(_id); - } - - /** - @notice Shows assets conversion output from withdrawing assets - @param id uint256 token id of token - @param assets Total number of assets - */ - function previewWithdraw(uint256 id, uint256 assets) - public - view - virtual - returns (uint256) - {} -} diff --git a/test/legacy_v1/Vault.sol b/test/legacy_v1/Vault.sol deleted file mode 100644 index 8804ee5d..00000000 --- a/test/legacy_v1/Vault.sol +++ /dev/null @@ -1,382 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import {SemiFungibleVault} from "./SemiFungibleVault.sol"; -import {ERC20} from "@solmate/tokens/ERC20.sol"; -import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol"; -import {IWETH} from "./interfaces/IWETH.sol"; -import { - ReentrancyGuard -} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; -import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol"; - -/// @author MiguelBits -contract Vault is SemiFungibleVault, ReentrancyGuard { - using FixedPointMathLib for uint256; - /*////////////////////////////////////////////////////////////// - ERRORS - //////////////////////////////////////////////////////////////*/ - error AddressZero(); - error AddressNotFactory(address _contract); - error AddressNotController(address _contract); - error MarketEpochDoesNotExist(); - error EpochAlreadyStarted(); - error EpochNotFinished(); - error FeeMoreThan150(uint256 _fee); - error ZeroValue(); - error OwnerDidNotAuthorize(address _sender, address _owner); - error EpochEndMustBeAfterBegin(); - error MarketEpochExists(); - error FeeCannotBe0(); - - /*/////////////////////////////////////////////////////////////// - IMMUTABLES AND STORAGE - //////////////////////////////////////////////////////////////*/ - - address public immutable tokenInsured; - address public treasury; - int256 public immutable strikePrice; - address public immutable factory; - address public controller; - - uint256[] public epochs; - - /*////////////////////////////////////////////////////////////// - MAPPINGS - //////////////////////////////////////////////////////////////*/ - - mapping(uint256 => uint256) public idFinalTVL; - mapping(uint256 => uint256) public idClaimTVL; - // @audit uint32 for timestamp is enough for the next 80 years - mapping(uint256 => uint256) public idEpochBegin; - // @audit id can be uint32 - mapping(uint256 => bool) public idEpochEnded; - // @audit id can be uint32 - mapping(uint256 => bool) public idExists; - mapping(uint256 => uint256) public epochFee; - mapping(uint256 => bool) public epochNull; - - /*////////////////////////////////////////////////////////////// - MODIFIERS - //////////////////////////////////////////////////////////////*/ - - /** @notice Only factory addresses can call functions that use this modifier - */ - modifier onlyFactory() { - if (msg.sender != factory) revert AddressNotFactory(msg.sender); - _; - } - - /** @notice Only controller addresses can call functions that use this modifier - */ - modifier onlyController() { - if (msg.sender != controller) revert AddressNotController(msg.sender); - _; - } - - /** @notice Only market addresses can call functions that use this modifier - */ - modifier marketExists(uint256 id) { - if (idExists[id] != true) revert MarketEpochDoesNotExist(); - _; - } - - /** @notice You can only call functions that use this modifier before the current epoch has started - */ - modifier epochHasNotStarted(uint256 id) { - if (block.timestamp >= idEpochBegin[id]) revert EpochAlreadyStarted(); - _; - } - - /** @notice You can only call functions that use this modifier after the current epoch has started - */ - modifier epochHasEnded(uint256 id) { - if (idEpochEnded[id] == false) revert EpochNotFinished(); - _; - } - - /*////////////////////////////////////////////////////////////// - CONSTRUCTOR - //////////////////////////////////////////////////////////////*/ - - /** - @notice constructor - @param _assetAddress token address representing your asset to be deposited; - @param _name token name for the ERC1155 mints. Insert the name of your token; Example: Y2K_USDC_1.2$ - @param _symbol token symbol for the ERC1155 mints. insert here if risk or hedge + Symbol. Example: HedgeY2K or riskY2K; - @param _token address of the oracle to lookup the price in chainlink oracles; - @param _strikePrice uint256 representing the price to trigger the depeg event; - @param _controller address of the controller contract, this contract can trigger the depeg events; - */ - constructor( - address _assetAddress, - string memory _name, - string memory _symbol, - address _treasury, - address _token, - int256 _strikePrice, - address _controller - ) SemiFungibleVault(ERC20(_assetAddress), _name, _symbol) { - if (_treasury == address(0)) revert AddressZero(); - - if (_controller == address(0)) revert AddressZero(); - - if (_token == address(0)) revert AddressZero(); - - tokenInsured = _token; - treasury = _treasury; - strikePrice = _strikePrice; - factory = msg.sender; - controller = _controller; - } - - /*/////////////////////////////////////////////////////////////// - DEPOSIT/WITHDRAWAL LOGIC - //////////////////////////////////////////////////////////////*/ - - /** - @notice Deposit function from ERC4626, with payment of a fee to a treasury implemented; - @param id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000; - @param assets uint256 representing how many assets the user wants to deposit, a fee will be taken from this value; - @param receiver address of the receiver of the assets provided by this function, that represent the ownership of the deposited asset; - */ - function deposit( - uint256 id, - uint256 assets, - address receiver - ) public override marketExists(id) epochHasNotStarted(id) nonReentrant { - if (receiver == address(0)) revert AddressZero(); - assert(asset.transferFrom(msg.sender, address(this), assets)); - - _mint(receiver, id, assets, EMPTY); - - emit Deposit(msg.sender, receiver, id, assets); - } - - /** - @notice Deposit ETH function - @param id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000; - @param receiver address of the receiver of the shares provided by this function, that represent the ownership of the deposited asset; - */ - function depositETH(uint256 id, address receiver) - external - payable - marketExists(id) - epochHasNotStarted(id) - nonReentrant - { - require(msg.value > 0, "ZeroValue"); - if (receiver == address(0)) revert AddressZero(); - - IWETH(address(asset)).deposit{value: msg.value}(); - _mint(receiver, id, msg.value, EMPTY); - - emit Deposit(msg.sender, receiver, id, msg.value); - } - - /** - @notice Withdraw entitled deposited assets, checking if a depeg event - @param id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000; - @param assets uint256 of how many assets you want to withdraw, this value will be used to calculate how many assets you are entitle to according to the events; - @param receiver Address of the receiver of the assets provided by this function, that represent the ownership of the transfered asset; - @param owner Address of the owner of these said assets; - @return shares How many shares the owner is entitled to, according to the conditions; - */ - function withdraw( - uint256 id, - uint256 assets, - address receiver, - address owner - ) - external - override - epochHasEnded(id) - marketExists(id) - returns (uint256 shares) - { - if (receiver == address(0)) revert AddressZero(); - - if (msg.sender != owner && isApprovedForAll(owner, msg.sender) == false) - revert OwnerDidNotAuthorize(msg.sender, owner); - - uint256 entitledShares; - _burn(owner, id, assets); - - if (epochNull[id] == false) { - entitledShares = previewWithdraw(id, assets); - //Taking fee from the premium - if (entitledShares > assets) { - uint256 premium = entitledShares - assets; - uint256 feeValue = calculateWithdrawalFeeValue(premium, id); - entitledShares = entitledShares - feeValue; - assert(asset.transfer(treasury, feeValue)); - } - } else { - entitledShares = assets; - } - if (entitledShares > 0) { - assert(asset.transfer(receiver, entitledShares)); - } - - emit Withdraw(msg.sender, receiver, owner, id, assets, entitledShares); - - return entitledShares; - } - - /*/////////////////////////////////////////////////////////////// - ACCOUNTING LOGIC - //////////////////////////////////////////////////////////////*/ - - /** - @notice returns total assets for the id of given epoch - @param _id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000; - */ - function totalAssets(uint256 _id) - public - view - override - marketExists(_id) - returns (uint256) - { - return totalSupply(_id); - } - - /** - @notice Calculates how much ether the %fee is taking from @param amount - @param amount Amount to withdraw from vault - @param _epoch Target epoch - @return feeValue Current fee value - */ - function calculateWithdrawalFeeValue(uint256 amount, uint256 _epoch) - public - view - returns (uint256 feeValue) - { - // 0.5% = multiply by 1000 then divide by 5 - return amount.mulDivUp(epochFee[_epoch], 1000); - } - - /*/////////////////////////////////////////////////////////////// - Factory FUNCTIONS - //////////////////////////////////////////////////////////////*/ - - /** - @notice Factory function, changes treasury address - @param _treasury New treasury address - */ - function changeTreasury(address _treasury) public onlyFactory { - if (_treasury == address(0)) revert AddressZero(); - treasury = _treasury; - } - - /** - @notice Factory function, changes controller address - @param _controller New controller address - */ - function changeController(address _controller) public onlyFactory { - if (_controller == address(0)) revert AddressZero(); - controller = _controller; - } - - /** - @notice Function to deploy hedge assets for given epochs, after the creation of this vault - @param epochBegin uint256 in UNIX timestamp, representing the begin date of the epoch. Example: Epoch begins in 31/May/2022 at 00h 00min 00sec: 1654038000 - @param epochEnd uint256 in UNIX timestamp, representing the end date of the epoch and also the ID for the minting functions. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1656630000 - @param _withdrawalFee uint256 of the fee value, multiply your % value by 10, Example: if you want fee of 0.5% , insert 5 - */ - function createAssets( - uint256 epochBegin, - uint256 epochEnd, - uint256 _withdrawalFee - ) public onlyFactory { - if (_withdrawalFee > 150) revert FeeMoreThan150(_withdrawalFee); - - if (_withdrawalFee == 0) revert FeeCannotBe0(); - - if (idExists[epochEnd] == true) revert MarketEpochExists(); - - if (epochBegin >= epochEnd) revert EpochEndMustBeAfterBegin(); - - idExists[epochEnd] = true; - idEpochBegin[epochEnd] = epochBegin; - epochs.push(epochEnd); - - epochFee[epochEnd] = _withdrawalFee; - } - - /*/////////////////////////////////////////////////////////////// - CONTROLLER LOGIC - //////////////////////////////////////////////////////////////*/ - - /** - @notice Controller can call this function to trigger the end of the epoch, storing the TVL of that epoch and if a depeg event occurred - @param id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000 - */ - function endEpoch(uint256 id) public onlyController marketExists(id) { - idEpochEnded[id] = true; - idFinalTVL[id] = totalAssets(id); - } - - /** - @notice Function to be called after endEpoch, by the Controller only, this function stores the TVL of the counterparty vault in a mapping to be used for later calculations of the entitled withdraw - @param id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000 - @param claimTVL uint256 representing the TVL the counterparty vault has, storing this value in a mapping - */ - function setClaimTVL(uint256 id, uint256 claimTVL) - public - onlyController - marketExists(id) - { - idClaimTVL[id] = claimTVL; - } - - /** - solhint-disable-next-line max-line-length - @notice Function to be called after endEpoch and setClaimTVL functions, respecting the calls in order, after storing the TVL of the end of epoch and the TVL amount to claim, this function will allow the transfer of tokens to the counterparty vault - @param id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000 - @param _counterparty Address of the other vault, meaning address of the risk vault, if this is an hedge vault, and vice-versa - */ - function sendTokens(uint256 id, address _counterparty) - public - onlyController - marketExists(id) - { - assert(asset.transfer(_counterparty, idFinalTVL[id])); - } - - function setEpochNull(uint256 id) public onlyController marketExists(id) { - epochNull[id] = true; - } - - /*/////////////////////////////////////////////////////////////// - INTERNAL HOOKS LOGIC - //////////////////////////////////////////////////////////////*/ - /** - @notice Shows assets conversion output from withdrawing assets - @param id uint256 token id of token - @param assets Total number of assets - */ - function previewWithdraw(uint256 id, uint256 assets) - public - view - override - returns (uint256 entitledAmount) - { - // in case the risk wins aka no depeg event - // risk users can withdraw the hedge (that is paid by the hedge buyers) and risk; withdraw = (risk + hedge) - // hedge pay for each hedge seller = ( risk / tvl before the hedge payouts ) * tvl in hedge pool - // in case there is a depeg event, the risk users can only withdraw the hedge - entitledAmount = assets.mulDivUp(idClaimTVL[id], idFinalTVL[id]); - // in case the hedge wins aka depegging - // hedge users pay the hedge to risk users anyway, - // hedge guy can withdraw risk (that is transfered from the risk pool), - // withdraw = % tvl that hedge buyer owns - // otherwise hedge users cannot withdraw any Eth - } - - /** @notice Lookup total epochs length - */ - function epochsLength() public view returns (uint256) { - return epochs.length; - } -} diff --git a/test/legacy_v1/VaultFactory.sol b/test/legacy_v1/VaultFactory.sol deleted file mode 100644 index e91908e9..00000000 --- a/test/legacy_v1/VaultFactory.sol +++ /dev/null @@ -1,654 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import {Vault} from "./Vault.sol"; -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -import {IController} from "./interfaces/IController.sol"; - -/// @author MiguelBits - -contract TimeLock { - mapping(bytes32 => bool) public queued; - - address public policy; - - uint256 public constant MIN_DELAY = 7 days; - uint256 public constant MAX_DELAY = 30 days; - uint256 public constant GRACE_PERIOD = 14 days; - - error NotOwner(address sender); - error AlreadyQueuedError(bytes32 txId); - error TimestampNotInRangeError(uint256 blocktimestamp, uint256 timestamp); - error NotQueuedError(bytes32 txId); - error TimestampNotPassedError(uint256 blocktimestamp, uint256 timestamp); - error TimestampExpiredError(uint256 blocktimestamp, uint256 timestamp); - error TxFailedError(string func); - - event Queue( - bytes32 indexed txId, - address indexed target, - string func, - uint256 index, - uint256 data, - address to, - address token, - uint256 timestamp - ); - - event Execute( - bytes32 indexed txId, - address indexed target, - string func, - uint256 index, - uint256 data, - address to, - address token, - uint256 timestamp - ); - - event Delete( - bytes32 indexed txId, - address indexed target, - string func, - uint256 index, - uint256 data, - address to, - address token, - uint256 timestamp - ); - - modifier onlyOwner() { - if (msg.sender != policy) revert NotOwner(msg.sender); - _; - } - - constructor(address _policy) { - policy = _policy; - } - - /** - * @dev leave params zero if not using them - * @notice Queue a transaction - * @param _target The target contract - * @param _func The function to call - * @param _index The market index of the vault to call the function on - * @param _data The data to pass to the function - * @param _to The address to change the params to - * @param _token The token to change the params to - * @param _timestamp The timestamp to execute the transaction - */ - function queue( - address _target, - string calldata _func, - uint256 _index, - uint256 _data, - address _to, - address _token, - uint256 _timestamp - ) external onlyOwner { - //create tx id - bytes32 txId = getTxId( - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ); - - //check tx id unique - if (queued[txId]) { - revert AlreadyQueuedError(txId); - } - - //check timestamp - if ( - _timestamp < block.timestamp + MIN_DELAY || - _timestamp > block.timestamp + MAX_DELAY - ) { - revert TimestampNotInRangeError(block.timestamp, _timestamp); - } - - //queue tx - queued[txId] = true; - - emit Queue( - txId, - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ); - } - - /** - * @dev leave params zero if not using them - * @notice Execute a Queued a transaction - * @param _target The target contract - * @param _func The function to call - * @param _index The market index of the vault to call the function on - * @param _data The data to pass to the function - * @param _to The address to change the params to - * @param _token The token to change the params to - * @param _timestamp The timestamp after which to execute the transaction - */ - function execute( - address _target, - string calldata _func, - uint256 _index, - uint256 _data, - address _to, - address _token, - uint256 _timestamp - ) external onlyOwner { - bytes32 txId = getTxId( - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ); - - //check tx id queued - if (!queued[txId]) { - revert NotQueuedError(txId); - } - - //check block.timestamp > timestamp - if (block.timestamp < _timestamp) { - revert TimestampNotPassedError(block.timestamp, _timestamp); - } - if (block.timestamp > _timestamp + GRACE_PERIOD) { - revert TimestampExpiredError( - block.timestamp, - _timestamp + GRACE_PERIOD - ); - } - - //delete tx from queue - queued[txId] = false; - - //execute tx - if (compareStringsbyBytes(_func, "changeTreasury")) { - VaultFactory(_target).changeTreasury(_to, _index); - } else if (compareStringsbyBytes(_func, "changeController")) { - VaultFactory(_target).changeController(_index, _to); - } else if (compareStringsbyBytes(_func, "changeOracle")) { - VaultFactory(_target).changeOracle(_token, _to); - } else { - revert TxFailedError(_func); - } - - emit Execute( - txId, - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ); - } - - function cancel( - address _target, - string calldata _func, - uint256 _index, - uint256 _data, - address _to, - address _token, - uint256 _timestamp - ) external onlyOwner { - bytes32 txId = getTxId( - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ); - - //check tx id queued - if (!queued[txId]) { - revert NotQueuedError(txId); - } - - //delete tx from queue - queued[txId] = false; - - emit Delete( - txId, - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ); - } - - function getTxId( - address _target, - string calldata _func, - uint256 _index, - uint256 _data, - address _to, - address _token, - uint256 _timestamp - ) public pure returns (bytes32 txId) { - return - keccak256( - abi.encode( - _target, - _func, - _index, - _data, - _to, - _token, - _timestamp - ) - ); - } - - function compareStringsbyBytes(string memory s1, string memory s2) - public - pure - returns (bool) - { - return - keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2)); - } - - function changeOwner(address _newOwner) external onlyOwner { - policy = _newOwner; - } -} - -contract VaultFactory is Ownable { - address public immutable WETH; - // solhint-enable var-name-mixedcase - address public treasury; - address public controller; - uint256 public marketIndex; - - TimeLock public timelocker; - - struct MarketVault { - uint256 index; - uint256 epochBegin; - uint256 epochEnd; - Vault hedge; - Vault risk; - uint256 withdrawalFee; - } - - /*////////////////////////////////////////////////////////////// - MODIFIERS - //////////////////////////////////////////////////////////////*/ - - modifier onlyTimeLocker() { - if (msg.sender != address(timelocker)) revert NotTimeLocker(); - _; - } - - /*////////////////////////////////////////////////////////////// - ERRORS - //////////////////////////////////////////////////////////////*/ - error MarketDoesNotExist(uint256 marketIndex); - error AddressZero(); - error AddressNotController(); - error AddressFactoryNotInController(); - error ControllerNotSet(); - error NotTimeLocker(); - error ControllerAlreadySet(); - - /*////////////////////////////////////////////////////////////// - EVENTS - //////////////////////////////////////////////////////////////*/ - - /** @notice Market is created when event is emitted - * @param mIndex Current market index - * @param hedge Hedge vault address - * @param risk Risk vault address - * @param token Token address - * @param name Market name - */ - event MarketCreated( - uint256 indexed mIndex, - address hedge, - address risk, - address token, - string name, - int256 strikePrice - ); - - /** @notice Epoch is created when event is emitted - * @param marketEpochId Current market epoch id - * @param mIndex Current market index - * @param startEpoch Epoch start time - * @param endEpoch Epoch end time - * @param hedge Hedge vault address - * @param risk Risk vault address - * @param token Token address - * @param name Market name - * @param strikePrice Vault strike price - */ - event EpochCreated( - bytes32 indexed marketEpochId, - uint256 indexed mIndex, - uint256 startEpoch, - uint256 endEpoch, - address hedge, - address risk, - address token, - string name, - int256 strikePrice, - uint256 withdrawalFee - ); - - /** @notice Controller is set when event is emitted - * @param newController Address for new controller - */ - event controllerSet(address indexed newController); - - /** @notice Treasury is changed when event is emitted - * @param _treasury Treasury address - * @param _marketIndex Target market index - */ - event changedTreasury(address _treasury, uint256 indexed _marketIndex); - - /** @notice Vault fee is changed when event is emitted - * @param _marketIndex Target market index - * @param _feeRate Target fee rate - */ - event changedVaultFee(uint256 indexed _marketIndex, uint256 _feeRate); - - /** @notice Controller is changed when event is emitted - * @param _marketIndex Target market index - * @param controller Target controller address - */ - event changedController( - uint256 indexed _marketIndex, - address indexed controller - ); - event changedOracle(address indexed _token, address _oracle); - - /*////////////////////////////////////////////////////////////// - MAPPINGS - //////////////////////////////////////////////////////////////*/ - - mapping(uint256 => address[]) public indexVaults; //[0] hedge and [1] risk vault - mapping(uint256 => uint256[]) public indexEpochs; //all epochs in the market - mapping(address => address) public tokenToOracle; //token address to respective oracle smart contract address - - /*////////////////////////////////////////////////////////////// - CONSTRUCTOR - //////////////////////////////////////////////////////////////*/ - - /** @notice Contract constructor - * @param _treasury Treasury address - * @param _weth Wrapped Ether token address - */ - constructor( - address _treasury, - address _weth, - address _policy - ) { - timelocker = new TimeLock(_policy); - - if (_weth == address(0)) revert AddressZero(); - - if (_treasury == address(0)) revert AddressZero(); - - WETH = _weth; - marketIndex = 0; - treasury = _treasury; - } - - /*////////////////////////////////////////////////////////////// - ADMIN FUNCTIONS - //////////////////////////////////////////////////////////////*/ - - /** - @notice Function to create two new vaults, hedge and risk, with the respective params, and storing the oracle for the token provided - @param _withdrawalFee uint256 of the fee value, multiply your % value by 10, Example: if you want fee of 0.5% , insert 5 - @param _token Address of the oracle to lookup the price in chainlink oracles - @param _strikePrice uint256 representing the price to trigger the depeg event, needs to be 18 decimals - @param epochBegin uint256 in UNIX timestamp, representing the begin date of the epoch. Example: Epoch begins in 31/May/2022 at 00h 00min 00sec: 1654038000 - @param epochEnd uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1656630000 - @param _oracle Address representing the smart contract to lookup the price of the given _token param - @return insr Address of the deployed hedge vault - @return rsk Address of the deployed risk vault - */ - function createNewMarket( - uint256 _withdrawalFee, - address _token, - int256 _strikePrice, - uint256 epochBegin, - uint256 epochEnd, - address _oracle, - string memory _name - ) public onlyOwner returns (address insr, address rsk) { - if (controller == address(0)) revert ControllerNotSet(); - - if (IController(controller).getVaultFactory() != address(this)) - revert AddressFactoryNotInController(); - - marketIndex += 1; - - //y2kUSDC_99*RISK or y2kUSDC_99*HEDGE - - Vault hedge = new Vault( - WETH, - string(abi.encodePacked(_name, "HEDGE")), - "hY2K", - treasury, - _token, - _strikePrice, - controller - ); - - Vault risk = new Vault( - WETH, - string(abi.encodePacked(_name, "RISK")), - "rY2K", - treasury, - _token, - _strikePrice, - controller - ); - - indexVaults[marketIndex] = [address(hedge), address(risk)]; - - if (tokenToOracle[_token] == address(0)) { - tokenToOracle[_token] = _oracle; - } - - emit MarketCreated( - marketIndex, - address(hedge), - address(risk), - _token, - _name, - _strikePrice - ); - - MarketVault memory marketVault = MarketVault( - marketIndex, - epochBegin, - epochEnd, - hedge, - risk, - _withdrawalFee - ); - - _createEpoch(marketVault); - - return (address(hedge), address(risk)); - } - - /** - @notice Function to deploy hedge assets for given epochs, after the creation of this vault, where the Index is the date of the end of epoch - @param index uint256 of the market index to create more assets in - @param epochBegin uint256 in UNIX timestamp, representing the begin date of the epoch. Example: Epoch begins in 31/May/2022 at 00h 00min 00sec: 1654038000 - @param epochEnd uint256 in UNIX timestamp, representing the end date of the epoch and also the ID for the minting functions. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1656630000 - @param _withdrawalFee uint256 of the fee value, multiply your % value by 10, Example: if you want fee of 0.5% , insert 5 - */ - function deployMoreAssets( - uint256 index, - uint256 epochBegin, - uint256 epochEnd, - uint256 _withdrawalFee - ) public onlyOwner { - if (controller == address(0)) revert ControllerNotSet(); - - if (index > marketIndex) { - revert MarketDoesNotExist(index); - } - address hedge = indexVaults[index][0]; - address risk = indexVaults[index][1]; - - MarketVault memory marketVault = MarketVault( - index, - epochBegin, - epochEnd, - Vault(hedge), - Vault(risk), - _withdrawalFee - ); - - _createEpoch(marketVault); - } - - function _createEpoch(MarketVault memory _marketVault) internal { - _marketVault.hedge.createAssets( - _marketVault.epochBegin, - _marketVault.epochEnd, - _marketVault.withdrawalFee - ); - _marketVault.risk.createAssets( - _marketVault.epochBegin, - _marketVault.epochEnd, - _marketVault.withdrawalFee - ); - - indexEpochs[_marketVault.index].push(_marketVault.epochEnd); - - emit EpochCreated( - keccak256( - abi.encodePacked( - _marketVault.index, - _marketVault.epochBegin, - _marketVault.epochEnd - ) - ), - _marketVault.index, - _marketVault.epochBegin, - _marketVault.epochEnd, - address(_marketVault.hedge), - address(_marketVault.risk), - _marketVault.hedge.tokenInsured(), - _marketVault.hedge.name(), - _marketVault.hedge.strikePrice(), - _marketVault.withdrawalFee - ); - } - - /** - @notice Admin function, sets the controller address one time use function only - @param _controller Address of the controller smart contract - */ - function setController(address _controller) public onlyOwner { - if (controller == address(0)) { - if (_controller == address(0)) revert AddressZero(); - controller = _controller; - - emit controllerSet(_controller); - } else { - revert ControllerAlreadySet(); - } - } - - /** - @notice Admin function, changes the assigned treasury address - @param _treasury Treasury address - @param _marketIndex Target market index - */ - function changeTreasury(address _treasury, uint256 _marketIndex) - public - onlyTimeLocker - { - if (_treasury == address(0)) revert AddressZero(); - - treasury = _treasury; - address[] memory vaults = indexVaults[_marketIndex]; - Vault insr = Vault(vaults[0]); - Vault risk = Vault(vaults[1]); - insr.changeTreasury(_treasury); - risk.changeTreasury(_treasury); - - emit changedTreasury(_treasury, _marketIndex); - } - - /** - @notice Admin function, changes controller address - @param _marketIndex Target market index - @param _controller Address of the controller smart contract - */ - function changeController(uint256 _marketIndex, address _controller) - public - onlyTimeLocker - { - if (_controller == address(0)) revert AddressZero(); - - address[] memory vaults = indexVaults[_marketIndex]; - Vault insr = Vault(vaults[0]); - Vault risk = Vault(vaults[1]); - insr.changeController(_controller); - risk.changeController(_controller); - - emit changedController(_marketIndex, _controller); - } - - /** - @notice Admin function, changes oracle address for a given token - @param _token Target token address - @param _oracle Oracle address - */ - function changeOracle(address _token, address _oracle) - public - onlyTimeLocker - { - if (_oracle == address(0)) revert AddressZero(); - if (_token == address(0)) revert AddressZero(); - - tokenToOracle[_token] = _oracle; - emit changedOracle(_token, _oracle); - } - - /*////////////////////////////////////////////////////////////// - GETTERS - //////////////////////////////////////////////////////////////*/ - - /** - @notice Function the retrieve the addresses of the hedge and risk vaults, in an array, in the respective order - @param index uint256 of the market index which to the vaults are associated to - @return vaults Address array of two vaults addresses, [0] being the hedge vault, [1] being the risk vault - */ - function getVaults(uint256 index) - public - view - returns (address[] memory vaults) - { - return indexVaults[index]; - } -} diff --git a/test/legacy_v1/VaultFactoryHelper.sol b/test/legacy_v1/VaultFactoryHelper.sol index e83407b7..161a63e1 100644 --- a/test/legacy_v1/VaultFactoryHelper.sol +++ b/test/legacy_v1/VaultFactoryHelper.sol @@ -2,10 +2,10 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory, TimeLock} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; -import {FakeOracle} from "./oracles/FakeOracle.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory, TimeLock} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; +import {FakeOracle} from "../oracles/FakeOracle.sol"; /// @author nexusflip /// @author MiguelBits diff --git a/test/legacy_v1/VaultFactoryTest.t.sol b/test/legacy_v1/VaultFactoryTest.t.sol index 4b878d78..71c7290e 100644 --- a/test/legacy_v1/VaultFactoryTest.t.sol +++ b/test/legacy_v1/VaultFactoryTest.t.sol @@ -2,11 +2,11 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; import {VaultFactoryHelper} from "./VaultFactoryHelper.sol"; -import {FakeOracle} from "./oracles/FakeOracle.sol"; +import {FakeOracle} from "../oracles/FakeOracle.sol"; /// @author nexusflip /// @author MiguelBits diff --git a/test/legacy_v1/VaultHelper.sol b/test/legacy_v1/VaultHelper.sol index 15fa6e54..478d85c6 100644 --- a/test/legacy_v1/VaultHelper.sol +++ b/test/legacy_v1/VaultHelper.sol @@ -2,10 +2,10 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory, TimeLock} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; -import {FakeOracle} from "./oracles/FakeOracle.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory, TimeLock} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; +import {FakeOracle} from "../oracles/FakeOracle.sol"; /// @author nexusflip /// @author MiguelBits diff --git a/test/legacy_v1/VaultTest.t.sol b/test/legacy_v1/VaultTest.t.sol index 71b3ca01..7599e8fb 100644 --- a/test/legacy_v1/VaultTest.t.sol +++ b/test/legacy_v1/VaultTest.t.sol @@ -2,11 +2,11 @@ pragma solidity 0.8.15; import "forge-std/Test.sol"; -import {Vault} from "../src/Vault.sol"; -import {VaultFactory, TimeLock} from "../src/VaultFactory.sol"; -import {Controller} from "../src/Controller.sol"; +import {Vault} from "../../src/legacy_v1/Vault.sol"; +import {VaultFactory, TimeLock} from "../../src/legacy_v1/VaultFactory.sol"; +import {Controller} from "../../src/legacy_v1/Controller.sol"; import {VaultHelper} from "./VaultHelper.sol"; -import {FakeOracle} from "./oracles/FakeOracle.sol"; +import {FakeOracle} from "../oracles/FakeOracle.sol"; import {ERC20} from "@solmate/tokens/ERC20.sol"; /// @author nexusflip diff --git a/test/legacy_v1/interfaces/IController.sol b/test/legacy_v1/interfaces/IController.sol deleted file mode 100644 index 744c070c..00000000 --- a/test/legacy_v1/interfaces/IController.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity 0.8.15; - -interface IController { - function getVaultFactory() external view returns (address); - - function triggerDepeg(uint256 marketIndex, uint256 epochEnd) external; - - function triggerEndEpoch(uint256 marketIndex, uint256 epochEnd) external; - - function triggerNullEpoch(uint256 marketIndex, uint256 epochEnd) external; -} diff --git a/test/legacy_v1/interfaces/IKeeper.sol b/test/legacy_v1/interfaces/IKeeper.sol deleted file mode 100644 index d2cab720..00000000 --- a/test/legacy_v1/interfaces/IKeeper.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.0; - -contract KeeperGelato { - function startTask(uint256 _marketIndex, uint256 _epochID) external {} - - function checker(uint256 _marketIndex, uint256 _epochID) - external - view - returns (bool canExec, bytes memory execPayload) - {} - - function deposit(uint256 _amount) external payable {} - - function withdraw(uint256 _amount) external {} -} diff --git a/test/legacy_v1/interfaces/IStakingRewards.sol b/test/legacy_v1/interfaces/IStakingRewards.sol deleted file mode 100644 index 2ca5af3e..00000000 --- a/test/legacy_v1/interfaces/IStakingRewards.sol +++ /dev/null @@ -1,26 +0,0 @@ -pragma solidity 0.8.15; - -// https://docs.synthetix.io/contracts/source/interfaces/istakingrewards -interface IStakingRewards { - // Mutative - function exit() external; - - function getReward() external; - - function stake(uint256 amount) external; - - function withdraw(uint256 amount) external; - - // Views - function balanceOf(address account) external view returns (uint256); - - function earned(address account) external view returns (uint256); - - function getRewardForDuration() external view returns (uint256); - - function lastTimeRewardApplicable() external view returns (uint256); - - function rewardPerToken() external view returns (uint256); - - function totalSupply() external view returns (uint256); -} diff --git a/test/legacy_v1/interfaces/IVault.sol b/test/legacy_v1/interfaces/IVault.sol deleted file mode 100644 index 384b96f5..00000000 --- a/test/legacy_v1/interfaces/IVault.sol +++ /dev/null @@ -1,173 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -/// @author MiguelBits -contract IVault { - /*////////////////////////////////////////////////////////////// - ERRORS - //////////////////////////////////////////////////////////////*/ - error AddressZero(); - error AddressNotFactory(address _contract); - error AddressNotController(address _contract); - error MarketEpochDoesNotExist(); - error EpochAlreadyStarted(); - error EpochNotFinished(); - error FeeMoreThan150(uint256 _fee); - error ZeroValue(); - error OwnerDidNotAuthorize(address _sender, address _owner); - error EpochEndMustBeAfterBegin(); - error MarketEpochExists(); - error FeeCannotBe0(); - - /*/////////////////////////////////////////////////////////////// - AND STORAGE - //////////////////////////////////////////////////////////////*/ - - address public tokenInsured; - address public treasury; - int256 public strikePrice; - address public factory; - address public controller; - - uint256[] public epochs; - uint256 public timewindow; - - /*////////////////////////////////////////////////////////////// - MAPPINGS - //////////////////////////////////////////////////////////////*/ - - mapping(uint256 => uint256) public idFinalTVL; - mapping(uint256 => uint256) public idClaimTVL; - // @audit uint32 for timestamp is enough for the next 80 years - mapping(uint256 => uint256) public idEpochBegin; - // @audit id can be uint32 - mapping(uint256 => bool) public idEpochEnded; - // @audit id can be uint32 - mapping(uint256 => bool) public idExists; - mapping(uint256 => uint256) public epochFee; - mapping(uint256 => bool) public epochNull; - - /*/////////////////////////////////////////////////////////////// - DEPOSIT/WITHDRAWAL LOGIC - //////////////////////////////////////////////////////////////*/ - - /** - @notice Deposit function from ERC4626, with payment of a fee to a treasury implemented; - @param id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000; - @param assets uint256 representing how many assets the user wants to deposit, a fee will be taken from this value; - @param receiver address of the receiver of the assets provided by this function, that represent the ownership of the deposited asset; - */ - function deposit( - uint256 id, - uint256 assets, - address receiver - ) public {} - - /** - @notice Deposit ETH function - @param id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000; - @param receiver address of the receiver of the shares provided by this function, that represent the ownership of the deposited asset; - */ - function depositETH(uint256 id, address receiver) external payable {} - - /** - @notice Withdraw entitled deposited assets, checking if a depeg event - @param id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000; - @param assets uint256 of how many assets you want to withdraw, this value will be used to calculate how many assets you are entitle to according to the events; - @param receiver Address of the receiver of the assets provided by this function, that represent the ownership of the transfered asset; - @param owner Address of the owner of these said assets; - @return shares How many shares the owner is entitled to, according to the conditions; - */ - function withdraw( - uint256 id, - uint256 assets, - address receiver, - address owner - ) external returns (uint256 shares) {} - - /*/////////////////////////////////////////////////////////////// - ACCOUNTING LOGIC - //////////////////////////////////////////////////////////////*/ - - /** - @notice returns total assets for the id of given epoch - @param _id uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1654038000; - */ - function totalAssets(uint256 _id) public view returns (uint256) {} - - /** - @notice Calculates how much ether the %fee is taking from @param amount - @param amount Amount to withdraw from vault - @param _epoch Target epoch - @return feeValue Current fee value - */ - function calculateWithdrawalFeeValue(uint256 amount, uint256 _epoch) - public - view - returns (uint256 feeValue) - {} - - /*/////////////////////////////////////////////////////////////// - Factory FUNCTIONS - //////////////////////////////////////////////////////////////*/ - - /** - @notice Factory function, changes treasury address - @param _treasury New treasury address - */ - function changeTreasury(address _treasury) public {} - - /** - @notice Factory function, changes vault time window - @param _timewindow New vault time window - */ - function changeTimewindow(uint256 _timewindow) public {} - - /** - @notice Factory function, changes controller address - @param _controller New controller address - */ - function changeController(address _controller) public {} - - /** - @notice Function to deploy hedge assets for given epochs, after the creation of this vault - @param epochBegin uint256 in UNIX timestamp, representing the begin date of the epoch. Example: Epoch begins in 31/May/2022 at 00h 00min 00sec: 1654038000 - @param epochEnd uint256 in UNIX timestamp, representing the end date of the epoch and also the ID for the minting functions. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1656630000 - @param _withdrawalFee uint256 of the fee value, multiply your % value by 10, Example: if you want fee of 0.5% , insert 5 - */ - function createAssets( - uint256 epochBegin, - uint256 epochEnd, - uint256 _withdrawalFee - ) public {} - - /*/////////////////////////////////////////////////////////////// - INTERNAL HOOKS LOGIC - //////////////////////////////////////////////////////////////*/ - /** - @notice Shows assets conversion output from withdrawing assets - @param id uint256 token id of token - @param assets Total number of assets - */ - function previewWithdraw(uint256 id, uint256 assets) - public - view - returns (uint256 entitledAmount) - { - // in case the risk wins aka no depeg event - // risk users can withdraw the hedge (that is paid by the hedge buyers) and risk; withdraw = (risk + hedge) - // hedge pay for each hedge seller = ( risk / tvl before the hedge payouts ) * tvl in hedge pool - // in case there is a depeg event, the risk users can only withdraw the hedge - // in case the hedge wins aka depegging - // hedge users pay the hedge to risk users anyway, - // hedge guy can withdraw risk (that is transfered from the risk pool), - // withdraw = % tvl that hedge buyer owns - // otherwise hedge users cannot withdraw any Eth - } - - /** @notice Lookup total epochs length - */ - function epochsLength() public view returns (uint256) { - return epochs.length; - } -} diff --git a/test/legacy_v1/interfaces/IVaultFactory.sol b/test/legacy_v1/interfaces/IVaultFactory.sol deleted file mode 100644 index 7d32844d..00000000 --- a/test/legacy_v1/interfaces/IVaultFactory.sol +++ /dev/null @@ -1,221 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -/// @author MiguelBits - -contract TimeLock { - mapping(bytes32 => bool) public queued; - - error NotOwner(address sender); - error AlreadyQueuedError(bytes32 txId); - error TimestampNotInRangeError(uint256 blocktimestamp, uint256 timestamp); - error NotQueuedError(bytes32 txId); - error TimestampNotPassedError(uint256 blocktimestamp, uint256 timestamp); - error TimestampExpiredError(uint256 blocktimestamp, uint256 timestamp); - error TxFailedError(string func); - - event Queue( - bytes32 indexed txId, - address indexed target, - string func, - uint256 index, - uint256 data, - address to, - address token, - uint256 timestamp - ); - - event Execute( - bytes32 indexed txId, - address indexed target, - string func, - uint256 index, - uint256 data, - address to, - address token, - uint256 timestamp - ); - - event Delete( - bytes32 indexed txId, - address indexed target, - string func, - uint256 index, - uint256 data, - address to, - address token, - uint256 timestamp - ); - - /** - * @dev leave params zero if not using them - * @notice Queue a transaction - * @param _target The target contract - * @param _func The function to call - * @param _index The market index of the vault to call the function on - * @param _data The data to pass to the function - * @param _to The address to change the params to - * @param _token The token to change the params to - * @param _timestamp The timestamp to execute the transaction - */ - function queue( - address _target, - string calldata _func, - uint256 _index, - uint256 _data, - address _to, - address _token, - uint256 _timestamp - ) external {} - - /** - * @dev leave params zero if not using them - * @notice Execute a Queued a transaction - * @param _target The target contract - * @param _func The function to call - * @param _index The market index of the vault to call the function on - * @param _data The data to pass to the function - * @param _to The address to change the params to - * @param _token The token to change the params to - * @param _timestamp The timestamp after which to execute the transaction - */ - function execute( - address _target, - string calldata _func, - uint256 _index, - uint256 _data, - address _to, - address _token, - uint256 _timestamp - ) external {} - - function cancel( - address _target, - string calldata _func, - uint256 _index, - uint256 _data, - address _to, - address _token, - uint256 _timestamp - ) external {} - - function getTxId( - address _target, - string calldata _func, - uint256 _index, - uint256 _data, - address _to, - address _token, - uint256 _timestamp - ) public pure returns (bytes32 txId) {} - - function compareStringsbyBytes(string memory s1, string memory s2) - external - pure - returns (bool) - {} - - function changeOwner(address _newOwner) external {} -} - -contract IVaultFactory { - /*////////////////////////////////////////////////////////////// - MAPPINGS - //////////////////////////////////////////////////////////////*/ - - mapping(uint256 => address[]) public indexVaults; //[0] hedge and [1] risk vault - mapping(uint256 => uint256[]) public indexEpochs; //all epochs in the market - mapping(address => address) public tokenToOracle; //token address to respective oracle smart contract address - - /*////////////////////////////////////////////////////////////// - ADMIN FUNCTIONS - //////////////////////////////////////////////////////////////*/ - - /** - @notice Function to create two new vaults, hedge and risk, with the respective params, and storing the oracle for the token provided - @param _withdrawalFee uint256 of the fee value, multiply your % value by 10, Example: if you want fee of 0.5% , insert 5 - @param _token Address of the oracle to lookup the price in chainlink oracles - @param _strikePrice uint256 representing the price to trigger the depeg event, needs to be 18 decimals - @param epochBegin uint256 in UNIX timestamp, representing the begin date of the epoch. Example: Epoch begins in 31/May/2022 at 00h 00min 00sec: 1654038000 - @param epochEnd uint256 in UNIX timestamp, representing the end date of the epoch. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1656630000 - @param _oracle Address representing the smart contract to lookup the price of the given _token param - @return insr Address of the deployed hedge vault - @return rsk Address of the deployed risk vault - */ - function createNewMarket( - uint256 _withdrawalFee, - address _token, - int256 _strikePrice, - uint256 epochBegin, - uint256 epochEnd, - address _oracle, - string memory _name - ) public returns (address insr, address rsk) {} - - /** - @notice Function to deploy hedge assets for given epochs, after the creation of this vault, where the Index is the date of the end of epoch - @param index uint256 of the market index to create more assets in - @param epochBegin uint256 in UNIX timestamp, representing the begin date of the epoch. Example: Epoch begins in 31/May/2022 at 00h 00min 00sec: 1654038000 - @param epochEnd uint256 in UNIX timestamp, representing the end date of the epoch and also the ID for the minting functions. Example: Epoch ends in 30th June 2022 at 00h 00min 00sec: 1656630000 - @param _withdrawalFee uint256 of the fee value, multiply your % value by 10, Example: if you want fee of 0.5% , insert 5 - */ - function deployMoreAssets( - uint256 index, - uint256 epochBegin, - uint256 epochEnd, - uint256 _withdrawalFee - ) public {} - - /** - @notice Admin function, sets the controller address - @param _controller Address of the controller smart contract - */ - function setController(address _controller) public {} - - /** - @notice Admin function, changes the assigned treasury address - @param _treasury Treasury address - @param _marketIndex Target market index - */ - function changeTreasury(address _treasury, uint256 _marketIndex) public {} - - /** - @notice Admin function, changes vault time window - @param _marketIndex Target market index - @param _timewindow New time window - */ - function changeTimewindow(uint256 _marketIndex, uint256 _timewindow) - public - {} - - /** - @notice Admin function, changes controller address - @param _marketIndex Target market index - @param _controller Address of the controller smart contract - */ - function changeController(uint256 _marketIndex, address _controller) - public - {} - - /** - @notice Admin function, changes oracle address for a given token - @param _token Target token address - @param _oracle Oracle address - */ - function changeOracle(address _token, address _oracle) public {} - - /*////////////////////////////////////////////////////////////// - GETTERS - //////////////////////////////////////////////////////////////*/ - - /** - @notice Function the retrieve the addresses of the hedge and risk vaults, in an array, in the respective order - @param index uint256 of the market index which to the vaults are associated to - @return vaults Address array of two vaults addresses, [0] being the hedge vault, [1] being the risk vault - */ - function getVaults(uint256 index) - public - view - returns (address[] memory vaults) - {} -} diff --git a/test/legacy_v1/interfaces/IWETH.sol b/test/legacy_v1/interfaces/IWETH.sol deleted file mode 100644 index 7c247552..00000000 --- a/test/legacy_v1/interfaces/IWETH.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-only -pragma solidity 0.8.15; - -interface IWETH { - function deposit() external payable; - - function transfer(address to, uint256 value) external returns (bool); - - function withdraw(uint256) external; -} diff --git a/test/legacy_v1/rewards/IStakingRewards.sol b/test/legacy_v1/rewards/IStakingRewards.sol deleted file mode 100644 index 2ca5af3e..00000000 --- a/test/legacy_v1/rewards/IStakingRewards.sol +++ /dev/null @@ -1,26 +0,0 @@ -pragma solidity 0.8.15; - -// https://docs.synthetix.io/contracts/source/interfaces/istakingrewards -interface IStakingRewards { - // Mutative - function exit() external; - - function getReward() external; - - function stake(uint256 amount) external; - - function withdraw(uint256 amount) external; - - // Views - function balanceOf(address account) external view returns (uint256); - - function earned(address account) external view returns (uint256); - - function getRewardForDuration() external view returns (uint256); - - function lastTimeRewardApplicable() external view returns (uint256); - - function rewardPerToken() external view returns (uint256); - - function totalSupply() external view returns (uint256); -} diff --git a/test/legacy_v1/rewards/Owned.sol b/test/legacy_v1/rewards/Owned.sol deleted file mode 100644 index b2743aea..00000000 --- a/test/legacy_v1/rewards/Owned.sol +++ /dev/null @@ -1,47 +0,0 @@ -pragma solidity 0.8.15; - -// https://docs.synthetix.io/contracts/source/contracts/owned -contract Owned { - address public owner; - address public nominatedOwner; - - event OwnerNominated(address newOwner); - event OwnerChanged(address oldOwner, address newOwner); - - modifier onlyOwner() { - _onlyOwner(); - _; - } - - constructor(address _owner) { - require(_owner != address(0), "Owner address cannot be 0"); - owner = _owner; - emit OwnerChanged(address(0), _owner); - } - - function nominateNewOwner(address _owner) external onlyOwner { - nominatedOwner = _owner; - emit OwnerNominated(_owner); - - emit OwnerChanged(owner, nominatedOwner); - owner = nominatedOwner; - nominatedOwner = address(0); - } - - function acceptOwnership() external { - require( - msg.sender == nominatedOwner, - "You must be nominated before you can accept ownership" - ); - emit OwnerChanged(owner, nominatedOwner); - owner = nominatedOwner; - nominatedOwner = address(0); - } - - function _onlyOwner() private view { - require( - msg.sender == owner, - "Only the contract owner may perform this action" - ); - } -} diff --git a/test/legacy_v1/rewards/PausableRewardsFactory.sol b/test/legacy_v1/rewards/PausableRewardsFactory.sol deleted file mode 100644 index a47b9db9..00000000 --- a/test/legacy_v1/rewards/PausableRewardsFactory.sol +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import {StakingRewards} from "./PausableStakingRewards.sol"; -import {VaultFactory} from "../VaultFactory.sol"; -import {Vault} from "../Vault.sol"; -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; - -/// @author MiguelBits - -contract RewardsFactory is Ownable { - address public govToken; - address public factory; - - /*////////////////////////////////////////////////////////////// - ERRORS - //////////////////////////////////////////////////////////////*/ - - error MarketDoesNotExist(uint256 marketId); - error EpochDoesNotExist(); - - /*////////////////////////////////////////////////////////////// - EVENTS - //////////////////////////////////////////////////////////////*/ - - /** @notice Creates staking rewards when event is emitted - * @param marketEpochId Current market epoch ID - * @param mIndex Current market index - * @param hedgeFarm Hedge farm address - * @param riskFarm Risk farm address - */ - event CreatedStakingReward( - bytes32 indexed marketEpochId, - uint256 indexed mIndex, - address hedgeFarm, - address riskFarm - ); - - /** @notice Contract constructor - * @param _govToken Governance token address - * @param _factory VaultFactory address - */ - constructor(address _govToken, address _factory) { - govToken = _govToken; - factory = _factory; - } - - /*////////////////////////////////////////////////////////////// - METHODS - //////////////////////////////////////////////////////////////*/ - - /** @notice Trigger staking rewards event - * @param _marketIndex Target market index - * @param _epochEnd End of epoch set for market - * @return insr Insurance rewards address, first tuple address entry - * @return risk Risk rewards address, second tuple address entry - */ - function createStakingRewards(uint256 _marketIndex, uint256 _epochEnd) - external - onlyOwner - returns (address insr, address risk) - { - VaultFactory vaultFactory = VaultFactory(factory); - - address _insrToken = vaultFactory.getVaults(_marketIndex)[0]; - address _riskToken = vaultFactory.getVaults(_marketIndex)[1]; - - if (_insrToken == address(0) || _riskToken == address(0)) - revert MarketDoesNotExist(_marketIndex); - - if ( - Vault(_insrToken).idExists(_epochEnd) == false || - Vault(_riskToken).idExists(_epochEnd) == false - ) revert EpochDoesNotExist(); - - StakingRewards insrStake = new StakingRewards( - owner(), - owner(), - govToken, - _insrToken, - _epochEnd - ); - StakingRewards riskStake = new StakingRewards( - owner(), - owner(), - govToken, - _riskToken, - _epochEnd - ); - - emit CreatedStakingReward( - keccak256( - abi.encodePacked( - _marketIndex, - Vault(_insrToken).idEpochBegin(_epochEnd), - _epochEnd - ) - ), - _marketIndex, - address(insrStake), - address(riskStake) - ); - - return (address(insrStake), address(riskStake)); - } -} diff --git a/test/legacy_v1/rewards/PausableStakingRewards.sol b/test/legacy_v1/rewards/PausableStakingRewards.sol deleted file mode 100644 index 891ea9fe..00000000 --- a/test/legacy_v1/rewards/PausableStakingRewards.sol +++ /dev/null @@ -1,244 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; -import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol"; -import { - ReentrancyGuard -} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; - -// Inheritance -import {IStakingRewards} from "./IStakingRewards.sol"; -import {RewardsDistributionRecipient} from "./RewardsDistributionRecipient.sol"; -import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; -import { - ERC1155Holder -} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; -import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; -import {ERC20} from "@solmate/tokens/ERC20.sol"; -import "./Owned.sol"; - -// https://docs.synthetix.io/contracts/source/contracts/stakingrewards - -contract StakingRewards is - IStakingRewards, - RewardsDistributionRecipient, - ReentrancyGuard, - Pausable, - ERC1155Holder -{ - using SafeMath for uint256; - using SafeTransferLib for ERC20; - - /* ========== STATE VARIABLES ========== */ - - ERC20 public immutable rewardsToken; - IERC1155 public immutable stakingToken; - uint256 public periodFinish = 0; - uint256 public rewardRate; - uint256 public rewardsDuration; - uint256 public lastUpdateTime; - uint256 public rewardPerTokenStored; - uint256 public id; - - mapping(address => uint256) public userRewardPerTokenPaid; - mapping(address => uint256) public rewards; - - uint256 private _totalSupply; - mapping(address => uint256) private _balances; - - /* ========== EVENTS ========== */ - - event RewardAdded(uint256 reward); - event Staked(address indexed user, uint256 id, uint256 amount); - event Withdrawn(address indexed user, uint256 id, uint256 amount); - event RewardPaid(address indexed user, uint256 reward); - event RewardsDurationUpdated(uint256 newDuration); - event Recovered(address token, uint256 amount); - - /* ========== MODIFIERS ========== */ - - modifier updateReward(address account) { - rewardPerTokenStored = rewardPerToken(); - lastUpdateTime = lastTimeRewardApplicable(); - if (account != address(0)) { - rewards[account] = earned(account); - userRewardPerTokenPaid[account] = rewardPerTokenStored; - } - _; - } - - /* ========== CONSTRUCTOR ========== */ - - constructor( - address _owner, - address _rewardsDistribution, - address _rewardsToken, - address _stakingToken, - uint256 _epochEnd - ) Owned(_owner) { - _pause(); - rewardsToken = ERC20(_rewardsToken); - stakingToken = IERC1155(_stakingToken); - rewardsDistribution = _rewardsDistribution; - id = _epochEnd; - rewardsDuration = _epochEnd - block.timestamp; - } - - /* ========== MUTATIVE FUNCTIONS ========== */ - function stake(uint256 amount) - external - nonReentrant - updateReward(msg.sender) - { - require(amount != 0, "Cannot stake 0"); - _totalSupply = _totalSupply.add(amount); - _balances[msg.sender] = _balances[msg.sender].add(amount); - stakingToken.safeTransferFrom( - msg.sender, - address(this), - id, - amount, - "" - ); - emit Staked(msg.sender, id, amount); - } - - function exit() external { - withdraw(_balances[msg.sender]); - getReward(); - } - - function withdraw(uint256 amount) - public - nonReentrant - updateReward(msg.sender) - { - require(amount > 0, "Cannot withdraw 0"); - _totalSupply = _totalSupply.sub(amount); - _balances[msg.sender] = _balances[msg.sender].sub(amount); - stakingToken.safeTransferFrom( - address(this), - msg.sender, - id, - amount, - "" - ); - emit Withdrawn(msg.sender, id, amount); - } - - function getReward() - public - nonReentrant - whenNotPaused - updateReward(msg.sender) - { - uint256 reward = rewards[msg.sender]; - if (reward > 0) { - rewards[msg.sender] = 0; - rewardsToken.safeTransfer(msg.sender, reward); - emit RewardPaid(msg.sender, reward); - } - } - - /* ========== VIEWS ========== */ - - function totalSupply() external view returns (uint256) { - return _totalSupply; - } - - function balanceOf(address account) external view returns (uint256) { - return _balances[account]; - } - - function getRewardForDuration() external view returns (uint256) { - return rewardRate.mul(rewardsDuration); - } - - function lastTimeRewardApplicable() public view returns (uint256) { - return block.timestamp < periodFinish ? block.timestamp : periodFinish; - } - - function rewardPerToken() public view returns (uint256) { - if (_totalSupply == 0) { - return rewardPerTokenStored; - } - return - rewardPerTokenStored.add( - lastTimeRewardApplicable() - .sub(lastUpdateTime) - .mul(rewardRate) - .mul(1e18) - .div(_totalSupply) - ); - } - - function earned(address account) public view returns (uint256) { - return - _balances[account] - .mul(rewardPerToken().sub(userRewardPerTokenPaid[account])) - .div(1e18) - .add(rewards[account]); - } - - /* ========== RESTRICTED FUNCTIONS ========== */ - - function notifyRewardAmount(uint256 reward) - external - override - onlyRewardsDistribution - updateReward(address(0)) - { - if (block.timestamp >= periodFinish) { - rewardRate = reward.div(rewardsDuration); - } else { - uint256 remaining = periodFinish.sub(block.timestamp); - uint256 leftover = remaining.mul(rewardRate); - rewardRate = reward.add(leftover).div(rewardsDuration); - } - - // Ensure the provided reward amount is not more than the balance in the contract. - // This keeps the reward rate in the right range, preventing overflows due to - // very high values of rewardRate in the earned and rewardsPerToken functions; - // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow. - uint256 balance = rewardsToken.balanceOf(address(this)); - require( - rewardRate <= balance.div(rewardsDuration), - "Provided reward too high" - ); - - lastUpdateTime = block.timestamp; - periodFinish = block.timestamp.add(rewardsDuration); - emit RewardAdded(reward); - } - - // Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders - function recoverERC20(address tokenAddress, uint256 tokenAmount) - external - onlyOwner - { - require( - tokenAddress != address(stakingToken), - "Cannot withdraw the staking token" - ); - ERC20(tokenAddress).safeTransfer(owner, tokenAmount); - emit Recovered(tokenAddress, tokenAmount); - } - - function setRewardsDuration(uint256 _rewardsDuration) external onlyOwner { - require( - block.timestamp > periodFinish, - "Previous rewards period must be complete before changing the duration for the new period" - ); - rewardsDuration = _rewardsDuration; - emit RewardsDurationUpdated(rewardsDuration); - } - - function pause() external onlyOwner { - _pause(); - } - - function unpause() external onlyOwner { - _unpause(); - } -} diff --git a/test/legacy_v1/rewards/RewardBalances.sol b/test/legacy_v1/rewards/RewardBalances.sol deleted file mode 100644 index 612586e3..00000000 --- a/test/legacy_v1/rewards/RewardBalances.sol +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; -import {StakingRewards} from "./StakingRewards.sol"; - -contract RewardBalances { - using SafeMath for uint256; - address[] public stakingRewardsContracts; - address public owner; - - /* ========== CONSTRUCTOR ========== */ - constructor(address[] memory _stakingRewardsContracts) { - stakingRewardsContracts = _stakingRewardsContracts; - owner = msg.sender; - } - - function balanceOf(address account) external view returns (uint256) { - uint256 balance; // initialize to 0 - - for (uint256 i; i < stakingRewardsContracts.length; i++) { // i initialize to 0 - balance = balance.add( - StakingRewards(stakingRewardsContracts[i]).earned(account) - ); - } - - return balance; - } - - function appendStakingContractAddress(address _stakingRewardsContract) - public - { - require(msg.sender == owner, "RewardBalances: FORBIDDEN"); - require(_stakingRewardsContract != address(0), "RewardBalances: ZERO_ADDRESS"); - - stakingRewardsContracts.push(_stakingRewardsContract); - } - - - function appendStakingContractAddressesLoop(address[] memory _stakingRewardsContracts) - external - { - require(msg.sender == owner, "RewardBalances: FORBIDDEN"); - - for (uint256 i; i < _stakingRewardsContracts.length; i++) { // initializes to 0 - appendStakingContractAddress(_stakingRewardsContracts[i]); - } - } - - function removeStakingContractAddress(uint8 _index) external { - require(msg.sender == owner, "RewardBalances: FORBIDDEN"); - require(_index <= stakingRewardsContracts.length-1, "RewardBalances: OUT_OF_BOUNDS"); - - delete stakingRewardsContracts[_index]; - } -} diff --git a/test/legacy_v1/rewards/RewardsDistributionRecipient.sol b/test/legacy_v1/rewards/RewardsDistributionRecipient.sol deleted file mode 100644 index 878479bf..00000000 --- a/test/legacy_v1/rewards/RewardsDistributionRecipient.sol +++ /dev/null @@ -1,26 +0,0 @@ -pragma solidity 0.8.15; - -// Inheritance -import "./Owned.sol"; - -// https://docs.synthetix.io/contracts/source/contracts/rewardsdistributionrecipient -abstract contract RewardsDistributionRecipient is Owned { - address public rewardsDistribution; - - modifier onlyRewardsDistribution() { - require( - msg.sender == rewardsDistribution, - "Caller is not RewardsDistribution contract" - ); - _; - } - - function notifyRewardAmount(uint256 reward) external virtual; - - function setRewardsDistribution(address _rewardsDistribution) - external - onlyOwner - { - rewardsDistribution = _rewardsDistribution; - } -} diff --git a/test/legacy_v1/rewards/RewardsFactory.sol b/test/legacy_v1/rewards/RewardsFactory.sol deleted file mode 100644 index 921bc7f6..00000000 --- a/test/legacy_v1/rewards/RewardsFactory.sol +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import {StakingRewards} from "./StakingRewards.sol"; -import {VaultFactory} from "../VaultFactory.sol"; -import {Vault} from "../Vault.sol"; -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; - -/// @author MiguelBits - -contract RewardsFactory is Ownable { - address public govToken; - address public factory; - - /*////////////////////////////////////////////////////////////// - ERRORS - //////////////////////////////////////////////////////////////*/ - - error MarketDoesNotExist(uint256 marketId); - error EpochDoesNotExist(); - - /*////////////////////////////////////////////////////////////// - EVENTS - //////////////////////////////////////////////////////////////*/ - - /** @notice Creates staking rewards when event is emitted - * @param marketEpochId Current market epoch ID - * @param mIndex Current market index - * @param hedgeFarm Hedge farm address - * @param riskFarm Risk farm address - */ - event CreatedStakingReward( - bytes32 indexed marketEpochId, - uint256 indexed mIndex, - address hedgeFarm, - address riskFarm - ); - - /** @notice Contract constructor - * @param _govToken Governance token address - * @param _factory VaultFactory address - */ - constructor(address _govToken, address _factory) { - govToken = _govToken; - factory = _factory; - } - - /*////////////////////////////////////////////////////////////// - METHODS - //////////////////////////////////////////////////////////////*/ - - /** @notice Trigger staking rewards event - * @param _marketIndex Target market index - * @param _epochEnd End of epoch set for market - * @return insr Insurance rewards address, first tuple address entry - * @return risk Risk rewards address, second tuple address entry - */ - function createStakingRewards(uint256 _marketIndex, uint256 _epochEnd) - external - onlyOwner - returns (address insr, address risk) - { - VaultFactory vaultFactory = VaultFactory(factory); - - address _insrToken = vaultFactory.getVaults(_marketIndex)[0]; - address _riskToken = vaultFactory.getVaults(_marketIndex)[1]; - - if (_insrToken == address(0) || _riskToken == address(0)) - revert MarketDoesNotExist(_marketIndex); - - if ( - Vault(_insrToken).idExists(_epochEnd) == false || - Vault(_riskToken).idExists(_epochEnd) == false - ) revert EpochDoesNotExist(); - - StakingRewards insrStake = new StakingRewards( - owner(), - owner(), - govToken, - _insrToken, - _epochEnd - ); - StakingRewards riskStake = new StakingRewards( - owner(), - owner(), - govToken, - _riskToken, - _epochEnd - ); - - emit CreatedStakingReward( - keccak256( - abi.encodePacked( - _marketIndex, - Vault(_insrToken).idEpochBegin(_epochEnd), - _epochEnd - ) - ), - _marketIndex, - address(insrStake), - address(riskStake) - ); - - return (address(insrStake), address(riskStake)); - } -} diff --git a/test/legacy_v1/rewards/StakingRewards.sol b/test/legacy_v1/rewards/StakingRewards.sol deleted file mode 100644 index e123e8bf..00000000 --- a/test/legacy_v1/rewards/StakingRewards.sol +++ /dev/null @@ -1,243 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; -import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol"; -import { - ReentrancyGuard -} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; - -// Inheritance -import {IStakingRewards} from "./IStakingRewards.sol"; -import {RewardsDistributionRecipient} from "./RewardsDistributionRecipient.sol"; -import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; -import { - ERC1155Holder -} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; -import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; -import {ERC20} from "@solmate/tokens/ERC20.sol"; -import "./Owned.sol"; - -// https://docs.synthetix.io/contracts/source/contracts/stakingrewards - -contract StakingRewards is - IStakingRewards, - RewardsDistributionRecipient, - ReentrancyGuard, - Pausable, - ERC1155Holder -{ - using SafeMath for uint256; - using SafeTransferLib for ERC20; - - /* ========== STATE VARIABLES ========== */ - - ERC20 public immutable rewardsToken; - IERC1155 public immutable stakingToken; - uint256 public periodFinish = 0; - uint256 public rewardRate; - uint256 public rewardsDuration; - uint256 public lastUpdateTime; - uint256 public rewardPerTokenStored; - uint256 public id; - - mapping(address => uint256) public userRewardPerTokenPaid; - mapping(address => uint256) public rewards; - - uint256 private _totalSupply; - mapping(address => uint256) private _balances; - - /* ========== EVENTS ========== */ - - event RewardAdded(uint256 reward); - event Staked(address indexed user, uint256 id, uint256 amount); - event Withdrawn(address indexed user, uint256 id, uint256 amount); - event RewardPaid(address indexed user, uint256 reward); - event RewardsDurationUpdated(uint256 newDuration); - event Recovered(address token, uint256 amount); - - /* ========== MODIFIERS ========== */ - - modifier updateReward(address account) { - rewardPerTokenStored = rewardPerToken(); - lastUpdateTime = lastTimeRewardApplicable(); - if (account != address(0)) { - rewards[account] = earned(account); - userRewardPerTokenPaid[account] = rewardPerTokenStored; - } - _; - } - - /* ========== CONSTRUCTOR ========== */ - - constructor( - address _owner, - address _rewardsDistribution, - address _rewardsToken, - address _stakingToken, - uint256 _epochEnd - ) Owned(_owner) { - rewardsToken = ERC20(_rewardsToken); - stakingToken = IERC1155(_stakingToken); - rewardsDistribution = _rewardsDistribution; - id = _epochEnd; - rewardsDuration = _epochEnd - block.timestamp; - } - - /* ========== MUTATIVE FUNCTIONS ========== */ - function stake(uint256 amount) - external - nonReentrant - updateReward(msg.sender) - { - require(amount != 0, "Cannot stake 0"); - _totalSupply = _totalSupply.add(amount); - _balances[msg.sender] = _balances[msg.sender].add(amount); - stakingToken.safeTransferFrom( - msg.sender, - address(this), - id, - amount, - "" - ); - emit Staked(msg.sender, id, amount); - } - - function exit() external { - withdraw(_balances[msg.sender]); - getReward(); - } - - function withdraw(uint256 amount) - public - nonReentrant - updateReward(msg.sender) - { - require(amount > 0, "Cannot withdraw 0"); - _totalSupply = _totalSupply.sub(amount); - _balances[msg.sender] = _balances[msg.sender].sub(amount); - stakingToken.safeTransferFrom( - address(this), - msg.sender, - id, - amount, - "" - ); - emit Withdrawn(msg.sender, id, amount); - } - - function getReward() - public - nonReentrant - whenNotPaused - updateReward(msg.sender) - { - uint256 reward = rewards[msg.sender]; - if (reward > 0) { - rewards[msg.sender] = 0; - rewardsToken.safeTransfer(msg.sender, reward); - emit RewardPaid(msg.sender, reward); - } - } - - /* ========== VIEWS ========== */ - - function totalSupply() external view returns (uint256) { - return _totalSupply; - } - - function balanceOf(address account) external view returns (uint256) { - return _balances[account]; - } - - function getRewardForDuration() external view returns (uint256) { - return rewardRate.mul(rewardsDuration); - } - - function lastTimeRewardApplicable() public view returns (uint256) { - return block.timestamp < periodFinish ? block.timestamp : periodFinish; - } - - function rewardPerToken() public view returns (uint256) { - if (_totalSupply == 0) { - return rewardPerTokenStored; - } - return - rewardPerTokenStored.add( - lastTimeRewardApplicable() - .sub(lastUpdateTime) - .mul(rewardRate) - .mul(1e18) - .div(_totalSupply) - ); - } - - function earned(address account) public view returns (uint256) { - return - _balances[account] - .mul(rewardPerToken().sub(userRewardPerTokenPaid[account])) - .div(1e18) - .add(rewards[account]); - } - - /* ========== RESTRICTED FUNCTIONS ========== */ - - function notifyRewardAmount(uint256 reward) - external - override - onlyRewardsDistribution - updateReward(address(0)) - { - if (block.timestamp >= periodFinish) { - rewardRate = reward.div(rewardsDuration); - } else { - uint256 remaining = periodFinish.sub(block.timestamp); - uint256 leftover = remaining.mul(rewardRate); - rewardRate = reward.add(leftover).div(rewardsDuration); - } - - // Ensure the provided reward amount is not more than the balance in the contract. - // This keeps the reward rate in the right range, preventing overflows due to - // very high values of rewardRate in the earned and rewardsPerToken functions; - // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow. - uint256 balance = rewardsToken.balanceOf(address(this)); - require( - rewardRate <= balance.div(rewardsDuration), - "Provided reward too high" - ); - - lastUpdateTime = block.timestamp; - periodFinish = block.timestamp.add(rewardsDuration); - emit RewardAdded(reward); - } - - // Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders - function recoverERC20(address tokenAddress, uint256 tokenAmount) - external - onlyOwner - { - require( - tokenAddress != address(stakingToken), - "Cannot withdraw the staking token" - ); - ERC20(tokenAddress).safeTransfer(owner, tokenAmount); - emit Recovered(tokenAddress, tokenAmount); - } - - function setRewardsDuration(uint256 _rewardsDuration) external onlyOwner { - require( - block.timestamp > periodFinish, - "Previous rewards period must be complete before changing the duration for the new period" - ); - rewardsDuration = _rewardsDuration; - emit RewardsDurationUpdated(rewardsDuration); - } - - function pause() external onlyOwner { - _pause(); - } - - function unpause() external onlyOwner { - _unpause(); - } -} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..2061ba95 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,580 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39" + integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/helper-validator-identifier@^7.18.6": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== + dependencies: + "@babel/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@solidity-parser/parser@^0.16.0": + version "0.16.0" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.16.0.tgz#1fb418c816ca1fc3a1e94b08bcfe623ec4e1add4" + integrity sha512-ESipEcHyRHg4Np4SqBCfcXwyxxna1DgFVz69bgpLV8vzl/NP1DtcKsJ4dJZXWQhY/Z4J2LeKBiOkOVZn9ct33Q== + dependencies: + antlr4ts "^0.5.0-alpha.4" + +ajv@^6.12.6: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.1: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +antlr4@^4.11.0: + version "4.12.0" + resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.12.0.tgz#e2323fbb057c77068a174914b0533398aeaba56a" + integrity sha512-23iB5IzXJZRZeK9TigzUyrNc9pSmNqAerJRBcNq1ETrmttMWRgaYZzC561IgEO3ygKsDJTYDTozABXa4b/fTQQ== + +antlr4ts@^0.5.0-alpha.4: + version "0.5.0-alpha.4" + resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" + integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +ast-parents@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" + integrity sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async@^2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +cosmiconfig@^8.0.0: + version "8.1.3" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.1.3.tgz#0e614a118fcc2d9e5afc2f87d53cd09931015689" + integrity sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw== + dependencies: + import-fresh "^3.2.1" + js-yaml "^4.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2, fast-diff@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +glob@^7.0.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^8.0.3: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +husky@^8.0.0: + version "8.0.3" + resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" + integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== + +ignore@^5.2.4: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier-plugin-solidity@*: + version "1.1.3" + resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.3.tgz#9a35124f578404caf617634a8cab80862d726cba" + integrity sha512-fQ9yucPi2sBbA2U2Xjh6m4isUTJ7S7QLc/XDDsktqqxYfTwdYKJ0EnnywXHwCGAaYbQNK+HIYPL1OemxuMsgeg== + dependencies: + "@solidity-parser/parser" "^0.16.0" + semver "^7.3.8" + solidity-comments-extractor "^0.0.7" + +prettier@^2.6.2, prettier@^2.8.3: + version "2.8.7" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.7.tgz#bb79fc8729308549d28fe3a98fce73d2c0656450" + integrity sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw== + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + integrity sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-pkg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-1.0.0.tgz#e19a15e78aca2e124461dc92b2e3943ef93494d9" + integrity sha512-L0/+vjdV3UjcQaXRlQcObpCyySS8GEqVNYGYRDAGlYOcw4J1y33WMIAD3XvYWIPnBeyN5Ilp5RHoifs3gR1S2g== + dependencies: + resolve-from "^2.0.0" + +scripty@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/scripty/-/scripty-2.1.1.tgz#41a9fb1472c042a4a631780df81dff079cdf8b15" + integrity sha512-yAutoO7+MfJcc7UAjAOp1CNbAI6GhxXYB63yFLEJe80BY1VkKQWrJ2xrdd57rh/UBnUIKmO31hzKUHWGxIupbA== + dependencies: + async "^2.6.4" + glob "^7.0.3" + lodash "^4.17.11" + resolve-pkg "^1.0.0" + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.8: + version "7.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0" + integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA== + dependencies: + lru-cache "^6.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +solhint-plugin-prettier@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/solhint-plugin-prettier/-/solhint-plugin-prettier-0.0.5.tgz#e3b22800ba435cd640a9eca805a7f8bc3e3e6a6b" + integrity sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA== + dependencies: + prettier-linter-helpers "^1.0.0" + +solhint@^3.3.7: + version "3.4.1" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.4.1.tgz#8ea15b21c13d1be0b53fd46d605a24d0b36a0c46" + integrity sha512-pzZn2RlZhws1XwvLPVSsxfHrwsteFf5eySOhpAytzXwKQYbTCJV6z8EevYDiSVKMpWrvbKpEtJ055CuEmzp4Xg== + dependencies: + "@solidity-parser/parser" "^0.16.0" + ajv "^6.12.6" + antlr4 "^4.11.0" + ast-parents "^0.0.1" + chalk "^4.1.2" + commander "^10.0.0" + cosmiconfig "^8.0.0" + fast-diff "^1.2.0" + glob "^8.0.3" + ignore "^5.2.4" + js-yaml "^4.1.0" + lodash "^4.17.21" + pluralize "^8.0.0" + semver "^6.3.0" + strip-ansi "^6.0.1" + table "^6.8.1" + text-table "^0.2.0" + optionalDependencies: + prettier "^2.8.3" + +solidity-comments-extractor@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" + integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== + +string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +table@^6.8.1: + version "6.8.1" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" + integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== From 6dd562d7e8269a8d3899901d180cb8a250f73241 Mon Sep 17 00:00:00 2001 From: y2kdev Date: Mon, 8 May 2023 14:20:40 -0400 Subject: [PATCH 30/31] fix compiler version issue --- test/oracles/FakeOracle.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/oracles/FakeOracle.sol b/test/oracles/FakeOracle.sol index e354e8f2..8e7c5413 100644 --- a/test/oracles/FakeOracle.sol +++ b/test/oracles/FakeOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-only -pragma solidity 0.8.17; +pragma solidity 0.8.15; import "@chainlink/interfaces/AggregatorV3Interface.sol"; From 73f03f3613969688480860643f859f540741a999 Mon Sep 17 00:00:00 2001 From: y2kdev Date: Mon, 29 May 2023 12:17:48 -0400 Subject: [PATCH 31/31] update version of legacy v1 --- src/legacy_v1/Controller.sol | 2 +- src/legacy_v1/SemiFungibleVault.sol | 2 +- src/legacy_v1/Vault.sol | 2 +- src/legacy_v1/VaultFactory.sol | 2 +- src/legacy_v1/interfaces/IController.sol | 2 +- src/legacy_v1/interfaces/IStakingRewards.sol | 2 +- src/legacy_v1/interfaces/IVault.sol | 2 +- src/legacy_v1/interfaces/IVaultFactory.sol | 2 +- src/legacy_v1/interfaces/IWETH.sol | 2 +- src/legacy_v1/rewards/IStakingRewards.sol | 2 +- src/legacy_v1/rewards/Owned.sol | 2 +- src/legacy_v1/rewards/PausableRewardsFactory.sol | 2 +- src/legacy_v1/rewards/PausableStakingRewards.sol | 2 +- src/legacy_v1/rewards/RewardBalances.sol | 2 +- src/legacy_v1/rewards/RewardsDistributionRecipient.sol | 2 +- src/legacy_v1/rewards/RewardsFactory.sol | 2 +- src/legacy_v1/rewards/StakingRewards.sol | 2 +- src/oracles/PegOracle.sol | 2 +- src/tokens/Y2K.sol | 2 +- test/legacy_v1/ControllerHelper.sol | 2 +- test/legacy_v1/ControllerTest.t.sol | 2 +- test/legacy_v1/GovToken.sol | 2 +- test/legacy_v1/LockTest.t.sol | 2 +- test/legacy_v1/OracleHelper.sol | 2 +- test/legacy_v1/OracleTest.t.sol | 2 +- test/legacy_v1/OwnerHelper.sol | 2 +- test/legacy_v1/OwnerTest.t.sol | 2 +- test/legacy_v1/RewardsBalanceHelper.sol | 2 +- test/legacy_v1/RewardsBalanceTest.t.sol | 2 +- test/legacy_v1/RewardsFactoryHelper.sol | 2 +- test/legacy_v1/RewardsFactoryTest.t.sol | 2 +- test/legacy_v1/VaultFactoryHelper.sol | 2 +- test/legacy_v1/VaultFactoryTest.t.sol | 2 +- test/legacy_v1/VaultHelper.sol | 2 +- test/legacy_v1/VaultTest.t.sol | 2 +- test/oracles/DepegOracle.sol | 2 +- test/oracles/FakeFakeOracle.sol | 2 +- test/oracles/FakeOracle.sol | 2 +- 38 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/legacy_v1/Controller.sol b/src/legacy_v1/Controller.sol index 04c92d99..96ed593c 100644 --- a/src/legacy_v1/Controller.sol +++ b/src/legacy_v1/Controller.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import {ERC20} from "@solmate/tokens/ERC20.sol"; import "./Vault.sol"; diff --git a/src/legacy_v1/SemiFungibleVault.sol b/src/legacy_v1/SemiFungibleVault.sol index 27514292..97235a83 100644 --- a/src/legacy_v1/SemiFungibleVault.sol +++ b/src/legacy_v1/SemiFungibleVault.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import {ERC20} from "@solmate/tokens/ERC20.sol"; import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol"; diff --git a/src/legacy_v1/Vault.sol b/src/legacy_v1/Vault.sol index 192ebb43..947d194f 100644 --- a/src/legacy_v1/Vault.sol +++ b/src/legacy_v1/Vault.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import {SemiFungibleVault} from "./SemiFungibleVault.sol"; import {ERC20} from "@solmate/tokens/ERC20.sol"; diff --git a/src/legacy_v1/VaultFactory.sol b/src/legacy_v1/VaultFactory.sol index e91908e9..eb2265ee 100644 --- a/src/legacy_v1/VaultFactory.sol +++ b/src/legacy_v1/VaultFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import {Vault} from "./Vault.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; diff --git a/src/legacy_v1/interfaces/IController.sol b/src/legacy_v1/interfaces/IController.sol index 744c070c..d5cd0aff 100644 --- a/src/legacy_v1/interfaces/IController.sol +++ b/src/legacy_v1/interfaces/IController.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-only -pragma solidity 0.8.15; +pragma solidity 0.8.17; interface IController { function getVaultFactory() external view returns (address); diff --git a/src/legacy_v1/interfaces/IStakingRewards.sol b/src/legacy_v1/interfaces/IStakingRewards.sol index 2ca5af3e..53c750c3 100644 --- a/src/legacy_v1/interfaces/IStakingRewards.sol +++ b/src/legacy_v1/interfaces/IStakingRewards.sol @@ -1,4 +1,4 @@ -pragma solidity 0.8.15; +pragma solidity 0.8.17; // https://docs.synthetix.io/contracts/source/interfaces/istakingrewards interface IStakingRewards { diff --git a/src/legacy_v1/interfaces/IVault.sol b/src/legacy_v1/interfaces/IVault.sol index 384b96f5..4de1bdd4 100644 --- a/src/legacy_v1/interfaces/IVault.sol +++ b/src/legacy_v1/interfaces/IVault.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; /// @author MiguelBits contract IVault { diff --git a/src/legacy_v1/interfaces/IVaultFactory.sol b/src/legacy_v1/interfaces/IVaultFactory.sol index 7d32844d..2bb23d8d 100644 --- a/src/legacy_v1/interfaces/IVaultFactory.sol +++ b/src/legacy_v1/interfaces/IVaultFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; /// @author MiguelBits diff --git a/src/legacy_v1/interfaces/IWETH.sol b/src/legacy_v1/interfaces/IWETH.sol index 7c247552..40040faa 100644 --- a/src/legacy_v1/interfaces/IWETH.sol +++ b/src/legacy_v1/interfaces/IWETH.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-only -pragma solidity 0.8.15; +pragma solidity 0.8.17; interface IWETH { function deposit() external payable; diff --git a/src/legacy_v1/rewards/IStakingRewards.sol b/src/legacy_v1/rewards/IStakingRewards.sol index 2ca5af3e..53c750c3 100644 --- a/src/legacy_v1/rewards/IStakingRewards.sol +++ b/src/legacy_v1/rewards/IStakingRewards.sol @@ -1,4 +1,4 @@ -pragma solidity 0.8.15; +pragma solidity 0.8.17; // https://docs.synthetix.io/contracts/source/interfaces/istakingrewards interface IStakingRewards { diff --git a/src/legacy_v1/rewards/Owned.sol b/src/legacy_v1/rewards/Owned.sol index b2743aea..4c948bd6 100644 --- a/src/legacy_v1/rewards/Owned.sol +++ b/src/legacy_v1/rewards/Owned.sol @@ -1,4 +1,4 @@ -pragma solidity 0.8.15; +pragma solidity 0.8.17; // https://docs.synthetix.io/contracts/source/contracts/owned contract Owned { diff --git a/src/legacy_v1/rewards/PausableRewardsFactory.sol b/src/legacy_v1/rewards/PausableRewardsFactory.sol index a47b9db9..1be82b85 100644 --- a/src/legacy_v1/rewards/PausableRewardsFactory.sol +++ b/src/legacy_v1/rewards/PausableRewardsFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import {StakingRewards} from "./PausableStakingRewards.sol"; import {VaultFactory} from "../VaultFactory.sol"; diff --git a/src/legacy_v1/rewards/PausableStakingRewards.sol b/src/legacy_v1/rewards/PausableStakingRewards.sol index 891ea9fe..f2e154ed 100644 --- a/src/legacy_v1/rewards/PausableStakingRewards.sol +++ b/src/legacy_v1/rewards/PausableStakingRewards.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol"; diff --git a/src/legacy_v1/rewards/RewardBalances.sol b/src/legacy_v1/rewards/RewardBalances.sol index 612586e3..1a56d5a2 100644 --- a/src/legacy_v1/rewards/RewardBalances.sol +++ b/src/legacy_v1/rewards/RewardBalances.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import {StakingRewards} from "./StakingRewards.sol"; diff --git a/src/legacy_v1/rewards/RewardsDistributionRecipient.sol b/src/legacy_v1/rewards/RewardsDistributionRecipient.sol index 878479bf..2c3130f4 100644 --- a/src/legacy_v1/rewards/RewardsDistributionRecipient.sol +++ b/src/legacy_v1/rewards/RewardsDistributionRecipient.sol @@ -1,4 +1,4 @@ -pragma solidity 0.8.15; +pragma solidity 0.8.17; // Inheritance import "./Owned.sol"; diff --git a/src/legacy_v1/rewards/RewardsFactory.sol b/src/legacy_v1/rewards/RewardsFactory.sol index 921bc7f6..ff051d4c 100644 --- a/src/legacy_v1/rewards/RewardsFactory.sol +++ b/src/legacy_v1/rewards/RewardsFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import {StakingRewards} from "./StakingRewards.sol"; import {VaultFactory} from "../VaultFactory.sol"; diff --git a/src/legacy_v1/rewards/StakingRewards.sol b/src/legacy_v1/rewards/StakingRewards.sol index e123e8bf..5458a65c 100644 --- a/src/legacy_v1/rewards/StakingRewards.sol +++ b/src/legacy_v1/rewards/StakingRewards.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol"; diff --git a/src/oracles/PegOracle.sol b/src/oracles/PegOracle.sol index 9f935180..3a61fc9c 100644 --- a/src/oracles/PegOracle.sol +++ b/src/oracles/PegOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "@chainlink/interfaces/AggregatorV3Interface.sol"; diff --git a/src/tokens/Y2K.sol b/src/tokens/Y2K.sol index 18a855c8..afb569b7 100644 --- a/src/tokens/Y2K.sol +++ b/src/tokens/Y2K.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import {ERC20} from "@solmate/tokens/ERC20.sol"; diff --git a/test/legacy_v1/ControllerHelper.sol b/test/legacy_v1/ControllerHelper.sol index 78f73090..165934cb 100644 --- a/test/legacy_v1/ControllerHelper.sol +++ b/test/legacy_v1/ControllerHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/ControllerTest.t.sol b/test/legacy_v1/ControllerTest.t.sol index cbc06332..8ed39420 100644 --- a/test/legacy_v1/ControllerTest.t.sol +++ b/test/legacy_v1/ControllerTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/GovToken.sol b/test/legacy_v1/GovToken.sol index 6d6788de..e1ca814f 100644 --- a/test/legacy_v1/GovToken.sol +++ b/test/legacy_v1/GovToken.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import {ERC20} from "@solmate/tokens/ERC20.sol"; diff --git a/test/legacy_v1/LockTest.t.sol b/test/legacy_v1/LockTest.t.sol index e414637b..55e2684b 100644 --- a/test/legacy_v1/LockTest.t.sol +++ b/test/legacy_v1/LockTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {LockRewards} from "../../src/lock-rewards/LockRewards.sol"; diff --git a/test/legacy_v1/OracleHelper.sol b/test/legacy_v1/OracleHelper.sol index fc05f828..c248e809 100644 --- a/test/legacy_v1/OracleHelper.sol +++ b/test/legacy_v1/OracleHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/OracleTest.t.sol b/test/legacy_v1/OracleTest.t.sol index 7da228a0..45aaf6fa 100644 --- a/test/legacy_v1/OracleTest.t.sol +++ b/test/legacy_v1/OracleTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/OwnerHelper.sol b/test/legacy_v1/OwnerHelper.sol index 06ae2efb..a2e5bf24 100644 --- a/test/legacy_v1/OwnerHelper.sol +++ b/test/legacy_v1/OwnerHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/OwnerTest.t.sol b/test/legacy_v1/OwnerTest.t.sol index 90961653..a2036ce8 100644 --- a/test/legacy_v1/OwnerTest.t.sol +++ b/test/legacy_v1/OwnerTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/RewardsBalanceHelper.sol b/test/legacy_v1/RewardsBalanceHelper.sol index 04a4098e..406fb05e 100644 --- a/test/legacy_v1/RewardsBalanceHelper.sol +++ b/test/legacy_v1/RewardsBalanceHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/RewardsBalanceTest.t.sol b/test/legacy_v1/RewardsBalanceTest.t.sol index f1b19665..56ce75cf 100644 --- a/test/legacy_v1/RewardsBalanceTest.t.sol +++ b/test/legacy_v1/RewardsBalanceTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/RewardsFactoryHelper.sol b/test/legacy_v1/RewardsFactoryHelper.sol index 8dfe86c7..daab3332 100644 --- a/test/legacy_v1/RewardsFactoryHelper.sol +++ b/test/legacy_v1/RewardsFactoryHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/RewardsFactoryTest.t.sol b/test/legacy_v1/RewardsFactoryTest.t.sol index a77bc07b..a2294dbd 100644 --- a/test/legacy_v1/RewardsFactoryTest.t.sol +++ b/test/legacy_v1/RewardsFactoryTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/VaultFactoryHelper.sol b/test/legacy_v1/VaultFactoryHelper.sol index 161a63e1..ed0147f7 100644 --- a/test/legacy_v1/VaultFactoryHelper.sol +++ b/test/legacy_v1/VaultFactoryHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/VaultFactoryTest.t.sol b/test/legacy_v1/VaultFactoryTest.t.sol index 71c7290e..cf035f71 100644 --- a/test/legacy_v1/VaultFactoryTest.t.sol +++ b/test/legacy_v1/VaultFactoryTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/VaultHelper.sol b/test/legacy_v1/VaultHelper.sol index 478d85c6..f14b08ef 100644 --- a/test/legacy_v1/VaultHelper.sol +++ b/test/legacy_v1/VaultHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/legacy_v1/VaultTest.t.sol b/test/legacy_v1/VaultTest.t.sol index 7599e8fb..43d3ce0a 100644 --- a/test/legacy_v1/VaultTest.t.sol +++ b/test/legacy_v1/VaultTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "forge-std/Test.sol"; import {Vault} from "../../src/legacy_v1/Vault.sol"; diff --git a/test/oracles/DepegOracle.sol b/test/oracles/DepegOracle.sol index 29c3d6a2..d96eb49d 100644 --- a/test/oracles/DepegOracle.sol +++ b/test/oracles/DepegOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-only -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "@chainlink/interfaces/AggregatorV3Interface.sol"; diff --git a/test/oracles/FakeFakeOracle.sol b/test/oracles/FakeFakeOracle.sol index 8f093512..84edd265 100644 --- a/test/oracles/FakeFakeOracle.sol +++ b/test/oracles/FakeFakeOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-only -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "@chainlink/interfaces/AggregatorV3Interface.sol"; diff --git a/test/oracles/FakeOracle.sol b/test/oracles/FakeOracle.sol index 8e7c5413..e354e8f2 100644 --- a/test/oracles/FakeOracle.sol +++ b/test/oracles/FakeOracle.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-only -pragma solidity 0.8.15; +pragma solidity 0.8.17; import "@chainlink/interfaces/AggregatorV3Interface.sol";