From 7f1375fa719539952fe6ad67de6283bf3e28428b Mon Sep 17 00:00:00 2001 From: Haythem Sellami Date: Thu, 15 Dec 2022 10:39:09 +0100 Subject: [PATCH] Revert "Add Borrowable Margin Pool (V2) (#459)" This reverts commit 841f81d9d05da9d27277b5775edfbb48c4012d2a. --- contracts/core/BorrowableMarginPool.sol | 354 -- contracts/core/Controller.sol | 109 +- contracts/interfaces/MarginPoolInterface.sol | 4 - .../longCallSpreadExpireItm.test.ts | 11 - .../longCallSpreadExpireOtm.test.ts | 8 - .../longCallSpreadPreExpiry.test.ts | 8 - .../longPutExpireItm.test.ts | 8 - .../longPutExpireOtm.test.ts | 8 - .../longPutPreExpiry.test.ts | 8 - ...CallExpireItm-borrowableMarginPool.test.ts | 328 -- .../nakedCallExpireItm.test.ts | 8 - ...CallExpireOtm-borrowableMarginPool.test.ts | 310 -- .../nakedCallExpireOtm.test.ts | 8 - ...CallPreExpiry-borrowableMarginPool.test.ts | 355 -- .../nakedCallPreExpiry.test.ts | 8 - .../nakedMarginCallPreExpiry.test.ts | 8 - .../nakedMarginPutPreExpiry.test.ts | 8 - .../nakedPutExpireITM.test.ts | 8 - .../nakedPutExpireOTM.test.ts | 8 - .../nakedPutPreExpiry.test.ts | 9 - .../open-markets-borrowableMarginPool.test.ts | 404 -- test/integration-tests/open-markets.test.ts | 8 - test/integration-tests/rollover.test.ts | 8 - .../shortCallSpreadExpireItm.test.ts | 8 - .../shortCallSpreadExpireOtm.test.ts | 8 - .../shortCallSpreadPreExpiry.test.ts | 8 - .../shortPutSpreadExpireItm.test.ts | 8 - .../shortPutSpreadExpireOtm.test.ts | 8 - .../shortPutSpreadPreExpiry.test.ts | 8 - test/integration-tests/yieldFarming.test.ts | 8 - test/unit-tests/borrowableMarginPool.test.ts | 1087 ---- test/unit-tests/controller.test.ts | 491 +- .../controllerBorrowableMarginPool.test.ts | 4889 ----------------- test/unit-tests/controllerNakedMargin.test.ts | 40 +- .../unit-tests/payableProxyController.test.ts | 34 +- 35 files changed, 208 insertions(+), 8385 deletions(-) delete mode 100644 contracts/core/BorrowableMarginPool.sol delete mode 100644 test/integration-tests/nakedCallExpireItm-borrowableMarginPool.test.ts delete mode 100644 test/integration-tests/nakedCallExpireOtm-borrowableMarginPool.test.ts delete mode 100644 test/integration-tests/nakedCallPreExpiry-borrowableMarginPool.test.ts delete mode 100644 test/integration-tests/open-markets-borrowableMarginPool.test.ts delete mode 100644 test/unit-tests/borrowableMarginPool.test.ts delete mode 100644 test/unit-tests/controllerBorrowableMarginPool.test.ts diff --git a/contracts/core/BorrowableMarginPool.sol b/contracts/core/BorrowableMarginPool.sol deleted file mode 100644 index bbcb5cdc7..000000000 --- a/contracts/core/BorrowableMarginPool.sol +++ /dev/null @@ -1,354 +0,0 @@ -/** - * SPDX-License-Identifier: UNLICENSED - */ -pragma solidity =0.6.10; - -import {ERC20Interface} from "../interfaces/ERC20Interface.sol"; -import {OtokenInterface} from "../interfaces/OtokenInterface.sol"; -import {AddressBookInterface} from "../interfaces/AddressBookInterface.sol"; -import {WhitelistInterface} from "../interfaces/WhitelistInterface.sol"; -import {SafeMath} from "../packages/oz/SafeMath.sol"; -import {SafeERC20} from "../packages/oz/SafeERC20.sol"; -import {MarginPool} from "./MarginPool.sol"; - -/** - * @author Ribbon Team - * @title MarginPoolV2 - * @notice Contract that holds all protocol funds AND allows collateral borrows - */ -contract BorrowableMarginPool is MarginPool { - using SafeMath for uint256; - using SafeERC20 for ERC20Interface; - - uint16 public constant TOTAL_PCT = 10000; // Equals 100% - - /// @dev mapping between collateral asset and borrow PCT - mapping(address => uint256) public borrowPCT; - /// @dev mapping between address and whitelist status of borrower - mapping(address => bool) internal whitelistedBorrower; - /// @dev mapping between address and whitelist status of otoken buyer - /// This is the whitelist for all the holders of oTokens that have a claim to - /// collateral in this pool - mapping(address => bool) internal whitelistedOTokenBuyer; - /// @dev mapping between address and whitelist status of options vault - /// This denotes whether an options vault can create a margin vault with - /// collateral custodied in this borrowable pool - mapping(address => bool) internal whitelistedOptionsVault; - /// @dev mapping between address and whether vault is a retail vault - mapping(address => bool) internal retailVaultStatus; - /// @dev mapping between (borrower, asset) and outstanding borrower amount - mapping(address => mapping(address => uint256)) public borrowed; - - /** - * @notice contructor - * @param _addressBook AddressBook module - */ - constructor(address _addressBook) public MarginPool(_addressBook) {} - - /// @notice emit event when a borrower is whitelisted / blacklisted - event SetBorrowWhitelist(address indexed borrower, bool whitelisted); - /// @notice emit event when a oToken buyer is whitelisted / blacklisted - event SetOTokenBuyerWhitelist(address indexed oTokenBuyer, bool whitelisted); - /// @notice emit event when a options vault is whitelisted / blacklisted - event SetOptionsVaultWhitelist(address indexed optionsVault, bool whitelisted); - /// @notice emit event when a options vault is set to retail status - event SetOptionsVaultToRetailStatus(address indexed optionsVault); - /// @notice emit event when borrowing percent has been changed - event SetBorrowPCT(address indexed collateralAsset, uint256 borrowPCT); - /// @notice emit event when a borrower borrows an asset - event Borrow(address indexed oToken, address indexed collateralAsset, uint256 amount, address indexed borrower); - /// @notice emit event when a loan is repaid - event Repay( - address indexed oToken, - address indexed collateralAsset, - uint256 amount, - address indexed borrower, - address repayer - ); - - /** - * @notice check if the sender is whitelisted - */ - modifier onlyWhitelistedBorrower() { - require(whitelistedBorrower[msg.sender], "MarginPool: Sender is not whitelisted borrower"); - - _; - } - - /** - * @notice check if a borrower is whitelisted - * @param _borrower address of the borrower - * @return boolean, True if the borrower is whitelisted - */ - function isWhitelistedBorrower(address _borrower) external view returns (bool) { - return whitelistedBorrower[_borrower]; - } - - /** - * @notice check if a oToken buyer is whitelisted - * @param _oTokenBuyer address of the oToken buyer - * @return boolean, True if the oToken buyer is whitelisted - */ - function isWhitelistedOTokenBuyer(address _oTokenBuyer) external view returns (bool) { - return whitelistedOTokenBuyer[_oTokenBuyer]; - } - - /** - * @notice check if a options vault is whitelisted - * @param _optionsVault address of the options vault - * @return boolean, True if the options vault is whitelisted - */ - function isWhitelistedOptionsVault(address _optionsVault) external view returns (bool) { - return whitelistedOptionsVault[_optionsVault]; - } - - /** - * @notice check if a options vault is retail vault - * @param _optionsVault address of the options vault - * @return boolean, True if the options vault is a retail vault - */ - function isRetailOptionsVault(address _optionsVault) external view returns (bool) { - return retailVaultStatus[_optionsVault]; - } - - /** - * @notice Set borrower whitelist status - * @param _borrower address of the borrower (100% of the time verified market makers) - * @param _whitelisted bool of whether it is whitelisted or blacklisted - */ - function setBorrowerWhitelistedStatus(address _borrower, bool _whitelisted) external onlyOwner { - require(_borrower != address(0), "MarginPool: Invalid Borrower"); - - whitelistedBorrower[_borrower] = _whitelisted; - emit SetBorrowWhitelist(_borrower, _whitelisted); - } - - /** - * @notice Set oToken buyer whitelist status - * @param _oTokenBuyer address of the oToken buyer - * @param _whitelisted bool of whether it is whitelisted or blacklisted - */ - function setOTokenBuyerWhitelistedStatus(address _oTokenBuyer, bool _whitelisted) external onlyOwner { - require(_oTokenBuyer != address(0), "MarginPool: Invalid oToken Buyer"); - - whitelistedOTokenBuyer[_oTokenBuyer] = _whitelisted; - emit SetOTokenBuyerWhitelist(_oTokenBuyer, _whitelisted); - } - - /** - * @notice Set options vault whitelist status - * @param _optionsVault address of the options vault - * @param _whitelisted bool of whether it is whitelisted or blacklisted - */ - function setOptionsVaultWhitelistedStatus(address _optionsVault, bool _whitelisted) external onlyOwner { - require(_optionsVault != address(0), "MarginPool: Invalid Options Vault"); - // Prevent whitelist of retail vault - require(!retailVaultStatus[_optionsVault], "MarginPool: Cannot whitelist a retail vault"); - - whitelistedOptionsVault[_optionsVault] = _whitelisted; - emit SetOptionsVaultWhitelist(_optionsVault, _whitelisted); - } - - /** - * @notice Set whether vault is a retail vault - * @param _optionsVaults address of the options vault - */ - function setOptionsVaultToRetailStatus(address[] calldata _optionsVaults) external onlyOwner { - for (uint256 i = 0; i < _optionsVaults.length; i++) { - if (_optionsVaults[i] == address(0) || retailVaultStatus[_optionsVaults[i]]) { - continue; - } - - // Prevents setting to false to avoid multisig risk of - // redirecting retail funds to borrowable margin pool - retailVaultStatus[_optionsVaults[i]] = true; - emit SetOptionsVaultToRetailStatus(_optionsVaults[i]); - } - } - - /** - * @notice Set Borrow percent of collateral asset - * @param _collateral address of collateral asset - * @param _borrowPCT borrow PCT - */ - function setBorrowPCT(address _collateral, uint256 _borrowPCT) external onlyOwner { - borrowPCT[_collateral] = _borrowPCT; - emit SetBorrowPCT(_collateral, _borrowPCT); - } - - /** - * @notice Lends out asset to market maker - * @param _oToken address of the oToken laying claim to the collateral assets - * @param _oTokenAmount amount of the oToken to post as collateral in exchange - */ - function borrow(address _oToken, uint256 _oTokenAmount) public onlyWhitelistedBorrower { - require( - WhitelistInterface(AddressBookInterface(addressBook).getWhitelist()).isWhitelistedOtoken(_oToken), - "MarginPool: oToken is not whitelisted" - ); - - require(_oTokenAmount > 0, "MarginPool: Cannot borrow 0 of underlying"); - - OtokenInterface oToken = OtokenInterface(_oToken); - - address collateralAsset = oToken.collateralAsset(); - uint256 outstandingAssetBorrow = borrowed[msg.sender][collateralAsset]; - - require(!oToken.isPut(), "MarginPool: oToken is not a call option"); - - // Make sure borrow does not attempt to borrow with an expired oToken - require( - oToken.expiryTimestamp() > block.timestamp, - "MarginPool: Cannot borrow collateral asset of expired oToken" - ); - - uint256 oTokenBalance = ERC20Interface(_oToken).balanceOf(msg.sender); - - // Each oToken represents 1:1 of collateral token - // So a market maker can borrow at most our oToken balance in the collateral asset - uint256 oTokenAmountCustodied = _collateralAssetToOTokenAmount(collateralAsset, outstandingAssetBorrow); - uint256 totalBorrowable = oTokenBalance.add(oTokenAmountCustodied).mul(borrowPCT[collateralAsset]).div( - TOTAL_PCT - ); - - require( - _oTokenAmount <= (totalBorrowable > oTokenAmountCustodied ? totalBorrowable.sub(oTokenAmountCustodied) : 0), - "MarginPool: Borrowing more than allocated" - ); - - uint256 collateralAssetAmount = _oTokenToCollateralAssetAmount(collateralAsset, _oTokenAmount); - - borrowed[msg.sender][collateralAsset] = outstandingAssetBorrow.add(collateralAssetAmount); - - // Decrease pool asset balance of collateralAsset - if (assetBalance[collateralAsset] > collateralAssetAmount) { - assetBalance[collateralAsset] = assetBalance[collateralAsset].sub(collateralAssetAmount); - } - - // transfer _oTokenAmount of oToken from borrower to _pool - ERC20Interface(_oToken).safeTransferFrom(msg.sender, address(this), _oTokenAmount); - // transfer collateralAssetAmount of collateralAsset from pool to borrower - ERC20Interface(collateralAsset).safeTransfer(msg.sender, collateralAssetAmount); - emit Borrow(_oToken, collateralAsset, collateralAssetAmount, msg.sender); - } - - /** - * @notice get the amount borrowable by market maker - * @param _borrower address of the borrower - * @param _oToken address of the oToken laying claim to the collateral assets - */ - function borrowable(address _borrower, address _oToken) external view returns (uint256) { - OtokenInterface oToken = OtokenInterface(_oToken); - address collateralAsset = oToken.collateralAsset(); - - uint256 outstandingAssetBorrow = borrowed[_borrower][collateralAsset]; - - uint256 collateralAllocatedToBorrower = _oTokenToCollateralAssetAmount( - collateralAsset, - ERC20Interface(_oToken).balanceOf(_borrower) - ); - - uint256 modifiedBal = collateralAllocatedToBorrower - .add(outstandingAssetBorrow) - .mul(borrowPCT[collateralAsset]) - .div(TOTAL_PCT); - return - whitelistedBorrower[_borrower] && - !oToken.isPut() && - oToken.expiryTimestamp() > block.timestamp && - modifiedBal > outstandingAssetBorrow - ? modifiedBal.sub(outstandingAssetBorrow) - : 0; - } - - /** - * @notice Repays asset back to pool before oToken expiry - * @param _oToken address of the oToken laying claim to the collateral assets - * @param _collateralAmount amount of the asset to repay - */ - function repay(address _oToken, uint256 _collateralAmount) public { - _repay(_oToken, _collateralAmount, msg.sender, msg.sender); - } - - /** - * @notice Repays asset back to pool for another borrower before oToken expiry - * @param _oToken address of the oToken laying claim to the collateral assets - * @param _collateralAmount amount of the asset to repay - * @param _borrower address of the borrower to repay for - */ - function repayFor( - address _oToken, - uint256 _collateralAmount, - address _borrower - ) public { - require(_borrower != address(0), "MarginPool: Borrower cannot be zero address"); - _repay(_oToken, _collateralAmount, _borrower, msg.sender); - } - - /** - * @notice Repays asset back to pool for another borrower before oToken expiry - * @param _oToken address of the oToken laying claim to the collateral assets - * @param _collateralAmount amount of the asset to repay - * @param _borrower address of the borrower to repay for - * @param _repayer address of the repayer of the loan - */ - function _repay( - address _oToken, - uint256 _collateralAmount, - address _borrower, - address _repayer - ) internal { - require(_collateralAmount > 0, "MarginPool: Cannot repay 0 of underlying"); - - address collateralAsset = OtokenInterface(_oToken).collateralAsset(); - uint256 outstandingAssetBorrow = borrowed[_borrower][collateralAsset]; - - require( - _collateralAmount <= outstandingAssetBorrow, - "MarginPool: Repaying more than outstanding borrow amount" - ); - - borrowed[_borrower][collateralAsset] = borrowed[_borrower][collateralAsset].sub(_collateralAmount); - - uint256 oTokensToRedeem = _collateralAssetToOTokenAmount(collateralAsset, _collateralAmount); - - // Increase pool asset balance of collateralAsset - assetBalance[collateralAsset] = assetBalance[collateralAsset].add(_collateralAmount); - - // transfer _amount of collateralAsset from borrower to pool - ERC20Interface(collateralAsset).safeTransferFrom(_repayer, address(this), _collateralAmount); - // transfer oTokensToRedeem of oToken from pool to _borrower - ERC20Interface(_oToken).safeTransfer(_borrower, oTokensToRedeem); - emit Repay(_oToken, collateralAsset, _collateralAmount, _borrower, _repayer); - } - - /** - * @notice Returns the equivalent in collateral asset amount (scale to `collateralAsset` decimals) - * @param _collateralAsset address of the collateral asset - * @param _amount amount to convert - */ - function _oTokenToCollateralAssetAmount(address _collateralAsset, uint256 _amount) internal view returns (uint256) { - uint256 collateralAssetDecimals = ERC20Interface(_collateralAsset).decimals(); - // If collateral asset has more decimals than oToken decimals (8), we scale up - // otherwise we scale down - return - collateralAssetDecimals >= 8 - ? _amount.mul(10**(collateralAssetDecimals.sub(8))) - : _amount.div(10**(uint256(8).sub(collateralAssetDecimals))); - } - - /** - * @notice Returns the equivalent in oToken amount (scale to 8 decimals) - * @param _collateralAsset address of the collateral asset - * @param _amount amount to convert - */ - function _collateralAssetToOTokenAmount(address _collateralAsset, uint256 _amount) internal view returns (uint256) { - uint256 collateralAssetDecimals = ERC20Interface(_collateralAsset).decimals(); - // If otoken has more decimals than collateral asset decimals, we scale down - // otherwise we scale up - return - collateralAssetDecimals >= 8 - ? _amount.div(10**(collateralAssetDecimals.sub(8))) - : _amount.mul(10**(uint256(8).sub(collateralAssetDecimals))); - } -} diff --git a/contracts/core/Controller.sol b/contracts/core/Controller.sol index d08fbdc73..8a1d4d837 100644 --- a/contracts/core/Controller.sol +++ b/contracts/core/Controller.sol @@ -12,7 +12,6 @@ import {SafeMath} from "../packages/oz/SafeMath.sol"; import {MarginVault} from "../libs/MarginVault.sol"; import {Actions} from "../libs/Actions.sol"; import {AddressBookInterface} from "../interfaces/AddressBookInterface.sol"; -import {ERC20Interface} from "../interfaces/ERC20Interface.sol"; import {OtokenInterface} from "../interfaces/OtokenInterface.sol"; import {MarginCalculatorInterface} from "../interfaces/MarginCalculatorInterface.sol"; import {OracleInterface} from "../interfaces/OracleInterface.sol"; @@ -30,6 +29,9 @@ import {CalleeInterface} from "../interfaces/CalleeInterface.sol"; * C6: msg.sender is not authorized to run action * C7: invalid addressbook address * C8: invalid owner address + * C9: invalid input + * C10: fullPauser cannot be set to address zero + * C11: partialPauser cannot be set to address zero * C12: can not run actions for different owners * C13: can not run actions on different vaults * C14: invalid final vault state @@ -72,7 +74,6 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade OracleInterface public oracle; MarginCalculatorInterface public calculator; MarginPoolInterface public pool; - MarginPoolInterface public borrowablePool; ///@dev scale used in MarginCalculator uint256 internal constant BASE = 8; @@ -102,8 +103,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade /******************************************************************** V2.0.0 storage upgrade ******************************************************/ - /// @dev mapping to map vault by each vault type - /// borrowable pool margin vault should be set to 2, naked margin vault should be set to 1, spread/max loss vault should be set to 0 + /// @dev mapping to map vault by each vault type, naked margin vault should be set to 1, spread/max loss vault should be set to 0 mapping(address => mapping(uint256 => uint256)) internal vaultType; /// @dev mapping to store the timestamp at which the vault was last updated, will be updated in every action that changes the vault state or when calling sync() mapping(address => mapping(uint256 => uint256)) internal vaultLatestUpdate; @@ -324,24 +324,14 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade emit Donated(msg.sender, _asset, _amount); } - /** - * @notice send asset amount to margin pool v2 - * @dev use donate() instead of direct transfer() to store the balance in assetBalance - * @param _asset asset address - * @param _amount amount to donate to pool - */ - function donateBorrowablePool(address _asset, uint256 _amount) external { - borrowablePool.transferToPool(_asset, msg.sender, _amount); - - emit Donated(msg.sender, _asset, _amount); - } - /** * @notice allows the partialPauser to toggle the systemPartiallyPaused variable and partially pause or partially unpause the system * @dev can only be called by the partialPauser * @param _partiallyPaused new boolean value to set systemPartiallyPaused to */ function setSystemPartiallyPaused(bool _partiallyPaused) external onlyPartialPauser { + require(systemPartiallyPaused != _partiallyPaused, "C9"); + systemPartiallyPaused = _partiallyPaused; emit SystemPartiallyPaused(systemPartiallyPaused); @@ -353,6 +343,8 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade * @param _fullyPaused new boolean value to set systemFullyPaused to */ function setSystemFullyPaused(bool _fullyPaused) external onlyFullPauser { + require(systemFullyPaused != _fullyPaused, "C9"); + systemFullyPaused = _fullyPaused; emit SystemFullyPaused(systemFullyPaused); @@ -364,6 +356,8 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade * @param _fullPauser new fullPauser address */ function setFullPauser(address _fullPauser) external onlyOwner { + require(_fullPauser != address(0), "C10"); + require(fullPauser != _fullPauser, "C9"); emit FullPauserUpdated(fullPauser, _fullPauser); fullPauser = _fullPauser; } @@ -374,6 +368,8 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade * @param _partialPauser new partialPauser address */ function setPartialPauser(address _partialPauser) external onlyOwner { + require(_partialPauser != address(0), "C11"); + require(partialPauser != _partialPauser, "C9"); emit PartialPauserUpdated(partialPauser, _partialPauser); partialPauser = _partialPauser; } @@ -385,6 +381,8 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade * @param _isRestricted new call restriction state */ function setCallRestriction(bool _isRestricted) external onlyOwner { + require(callRestricted != _isRestricted, "C9"); + callRestricted = _isRestricted; emit CallRestricted(callRestricted); @@ -397,6 +395,8 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade * @param _isOperator new boolean value that expresses if the sender is giving or revoking privileges for _operator */ function setOperator(address _operator, bool _isOperator) external { + require(operators[msg.sender][_operator] != _isOperator, "C9"); + operators[msg.sender][_operator] = _isOperator; emit AccountOperatorUpdated(msg.sender, _operator, _isOperator); @@ -458,6 +458,26 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade return operators[_owner][_operator]; } + /** + * @notice returns the current controller configuration + * @return whitelist, the address of the whitelist module + * @return oracle, the address of the oracle module + * @return calculator, the address of the calculator module + * @return pool, the address of the pool module + */ + function getConfiguration() + external + view + returns ( + address, + address, + address, + address + ) + { + return (address(whitelist), address(oracle), address(calculator), address(pool)); + } + /** * @notice return a vault's proceeds pre or post expiry, the amount of collateral that can be removed from a vault * @param _owner account owner of the vault @@ -698,7 +718,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade // store new vault accountVaultCounter[_args.owner] = vaultId; - vaultType[_args.owner][vaultId] = borrowablePool.isWhitelistedOptionsVault(_args.owner) ? 2 : _args.vaultType; + vaultType[_args.owner][vaultId] = _args.vaultType; emit VaultOpened(_args.owner, vaultId, _args.vaultType); } @@ -725,11 +745,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade vaults[_args.owner][_args.vaultId].addLong(_args.asset, _args.amount, _args.index); - MarginPoolInterface(_getPool(vaultType[_args.owner][_args.vaultId])).transferToPool( - _args.asset, - _args.from, - _args.amount - ); + pool.transferToPool(_args.asset, _args.from, _args.amount); emit LongOtokenDeposited(_args.asset, _args.owner, _args.from, _args.vaultId, _args.amount); } @@ -752,11 +768,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade vaults[_args.owner][_args.vaultId].removeLong(_args.asset, _args.amount, _args.index); - MarginPoolInterface(_getPool(vaultType[_args.owner][_args.vaultId])).transferToUser( - _args.asset, - _args.to, - _args.amount - ); + pool.transferToUser(_args.asset, _args.to, _args.amount); emit LongOtokenWithdrawed(_args.asset, _args.owner, _args.to, _args.vaultId, _args.amount); } @@ -787,11 +799,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade vaults[_args.owner][_args.vaultId].addCollateral(_args.asset, _args.amount, _args.index); - MarginPoolInterface(_getPool(vaultType[_args.owner][_args.vaultId])).transferToPool( - _args.asset, - _args.from, - _args.amount - ); + pool.transferToPool(_args.asset, _args.from, _args.amount); emit CollateralAssetDeposited(_args.asset, _args.owner, _args.from, _args.vaultId, _args.amount); } @@ -822,11 +830,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade vaults[_args.owner][_args.vaultId].removeCollateral(_args.asset, _args.amount, _args.index); - MarginPoolInterface(_getPool(vaultType[_args.owner][_args.vaultId])).transferToUser( - _args.asset, - _args.to, - _args.amount - ); + pool.transferToUser(_args.asset, _args.to, _args.amount); emit CollateralAssetWithdrawed(_args.asset, _args.owner, _args.to, _args.vaultId, _args.amount); } @@ -906,12 +910,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade otoken.burnOtoken(msg.sender, _args.amount); - MarginPoolInterface _pool = (!borrowablePool.isWhitelistedOTokenBuyer(msg.sender) || - ERC20Interface(collateral).balanceOf(address(borrowablePool)) < payout) - ? pool - : borrowablePool; - - _pool.transferToUser(collateral, _args.receiver, payout); + pool.transferToUser(collateral, _args.receiver, payout); emit Redeem(_args.otoken, msg.sender, _args.receiver, collateral, _args.amount, payout); } @@ -944,7 +943,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade if (hasLong) { OtokenInterface longOtoken = OtokenInterface(vault.longOtokens[0]); - longOtoken.burnOtoken(_getPool(vaultType[_args.owner][_args.vaultId]), vault.longAmounts[0]); + longOtoken.burnOtoken(address(pool), vault.longAmounts[0]); } } @@ -966,11 +965,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade nakedPoolBalance[collateral] = nakedPoolBalance[collateral].sub(payout); } - MarginPoolInterface(_getPool(vaultType[_args.owner][_args.vaultId])).transferToUser( - collateral, - _args.to, - payout - ); + pool.transferToUser(collateral, _args.to, payout); uint256 vaultId = _args.vaultId; address payoutRecipient = _args.to; @@ -1019,11 +1014,7 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade // decrease internal naked margin collateral amount nakedPoolBalance[vault.collateralAssets[0]] = nakedPoolBalance[vault.collateralAssets[0]].sub(collateralToSell); - MarginPoolInterface(_getPool(vaultType[_args.owner][_args.vaultId])).transferToUser( - vault.collateralAssets[0], - _args.receiver, - collateralToSell - ); + pool.transferToUser(vault.collateralAssets[0], _args.receiver, collateralToSell); emit VaultLiquidated( msg.sender, @@ -1159,15 +1150,5 @@ contract Controller is Initializable, OwnableUpgradeSafe, ReentrancyGuardUpgrade oracle = OracleInterface(addressbook.getOracle()); calculator = MarginCalculatorInterface(addressbook.getMarginCalculator()); pool = MarginPoolInterface(addressbook.getMarginPool()); - borrowablePool = MarginPoolInterface(addressbook.getAddress(keccak256("BORROWABLE_POOL"))); - } - - /** - * @dev checks correct pool for vault type. type 0 or 1: non-borrowable pool, type 2: borrowable pool - * @param _vaultType type of the vault - * @return margin pool corresponding to the vault - */ - function _getPool(uint256 _vaultType) internal view returns (address) { - return _vaultType < 2 ? address(pool) : address(borrowablePool); } } diff --git a/contracts/interfaces/MarginPoolInterface.sol b/contracts/interfaces/MarginPoolInterface.sol index 7a1aca185..7b3cfd6e5 100644 --- a/contracts/interfaces/MarginPoolInterface.sol +++ b/contracts/interfaces/MarginPoolInterface.sol @@ -9,10 +9,6 @@ interface MarginPoolInterface { function getStoredBalance(address _asset) external view returns (uint256); - function isWhitelistedOTokenBuyer(address _oTokenBuyer) external view returns (bool); - - function isWhitelistedOptionsVault(address _optionsVault) external view returns (bool); - /* Admin-only functions */ function setFarmer(address _farmer) external; diff --git a/test/integration-tests/longCallSpreadExpireItm.test.ts b/test/integration-tests/longCallSpreadExpireItm.test.ts index ea90ad10e..04d249f51 100644 --- a/test/integration-tests/longCallSpreadExpireItm.test.ts +++ b/test/integration-tests/longCallSpreadExpireItm.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Long Call Spread Option expires Itm flow', ([accountOwner1, nakedBuyer let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -85,11 +82,8 @@ contract('Long Call Spread Option expires Itm flow', ([accountOwner1, nakedBuyer addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() - // setup controllerProxy module await Controller.link('MarginVault', lib.address) controllerImplementation = await Controller.new(addressBook.address) @@ -113,9 +107,6 @@ contract('Long Call Spread Option expires Itm flow', ([accountOwner1, nakedBuyer await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) @@ -123,8 +114,6 @@ contract('Long Call Spread Option expires Itm flow', ([accountOwner1, nakedBuyer const controllerProxyAddress = await addressBook.getController() controllerProxy = await Controller.at(controllerProxyAddress) - // await controllerProxy.refreshConfiguration(); - await otokenFactory.createOtoken( weth.address, usdc.address, diff --git a/test/integration-tests/longCallSpreadExpireOtm.test.ts b/test/integration-tests/longCallSpreadExpireOtm.test.ts index ac98f37aa..bf4c0bc1a 100644 --- a/test/integration-tests/longCallSpreadExpireOtm.test.ts +++ b/test/integration-tests/longCallSpreadExpireOtm.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Long Call Spread Option expires Otm flow', ([accountOwner1, nakedBuyer let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: BorrowableMarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -84,8 +81,6 @@ contract('Long Call Spread Option expires Otm flow', ([accountOwner1, nakedBuyer addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -111,9 +106,6 @@ contract('Long Call Spread Option expires Otm flow', ([accountOwner1, nakedBuyer await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/longCallSpreadPreExpiry.test.ts b/test/integration-tests/longCallSpreadPreExpiry.test.ts index cb0367021..274234046 100644 --- a/test/integration-tests/longCallSpreadPreExpiry.test.ts +++ b/test/integration-tests/longCallSpreadPreExpiry.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Long Call Spread Option closed before expiry flow', ([accountOwner1, n let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -85,8 +82,6 @@ contract('Long Call Spread Option closed before expiry flow', ([accountOwner1, n addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -112,9 +107,6 @@ contract('Long Call Spread Option closed before expiry flow', ([accountOwner1, n await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/longPutExpireItm.test.ts b/test/integration-tests/longPutExpireItm.test.ts index 59f6685bc..17c1f55c3 100644 --- a/test/integration-tests/longPutExpireItm.test.ts +++ b/test/integration-tests/longPutExpireItm.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Long Put Spread Option closed ITM flow', ([accountOwner1, accountOwner let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -85,8 +82,6 @@ contract('Long Put Spread Option closed ITM flow', ([accountOwner1, accountOwner addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -112,9 +107,6 @@ contract('Long Put Spread Option closed ITM flow', ([accountOwner1, accountOwner await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/longPutExpireOtm.test.ts b/test/integration-tests/longPutExpireOtm.test.ts index 44270c23a..2f2f4017b 100644 --- a/test/integration-tests/longPutExpireOtm.test.ts +++ b/test/integration-tests/longPutExpireOtm.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Long Put Spread Option expires Otm flow', ([accountOwner1, nakedBuyer, let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -85,8 +82,6 @@ contract('Long Put Spread Option expires Otm flow', ([accountOwner1, nakedBuyer, addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -112,9 +107,6 @@ contract('Long Put Spread Option expires Otm flow', ([accountOwner1, nakedBuyer, await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/longPutPreExpiry.test.ts b/test/integration-tests/longPutPreExpiry.test.ts index cfbe9f69c..8b0ed74ad 100644 --- a/test/integration-tests/longPutPreExpiry.test.ts +++ b/test/integration-tests/longPutPreExpiry.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Long Put Spread Option closed before expiry flow', ([accountOwner1, bu let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -85,8 +82,6 @@ contract('Long Put Spread Option closed before expiry flow', ([accountOwner1, bu addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -112,9 +107,6 @@ contract('Long Put Spread Option closed before expiry flow', ([accountOwner1, bu await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/nakedCallExpireItm-borrowableMarginPool.test.ts b/test/integration-tests/nakedCallExpireItm-borrowableMarginPool.test.ts deleted file mode 100644 index 54f3f2f34..000000000 --- a/test/integration-tests/nakedCallExpireItm-borrowableMarginPool.test.ts +++ /dev/null @@ -1,328 +0,0 @@ -import { - MockERC20Instance, - MarginCalculatorInstance, - AddressBookInstance, - MockOracleInstance, - OtokenInstance, - ControllerInstance, - WhitelistInstance, - MarginPoolInstance, - BorrowableMarginPoolInstance, - OtokenFactoryInstance, -} from '../../build/types/truffle-types' -import { createTokenAmount, createValidExpiry } from '../utils' -import BigNumber from 'bignumber.js' - -const { time } = require('@openzeppelin/test-helpers') -const AddressBook = artifacts.require('AddressBook.sol') -const MockOracle = artifacts.require('MockOracle.sol') -const Otoken = artifacts.require('Otoken.sol') -const MockERC20 = artifacts.require('MockERC20.sol') -const MarginCalculator = artifacts.require('MarginCalculator.sol') -const Whitelist = artifacts.require('Whitelist.sol') -const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') -const Controller = artifacts.require('Controller.sol') -const MarginVault = artifacts.require('MarginVault.sol') -const OTokenFactory = artifacts.require('OtokenFactory.sol') -const ZERO_ADDR = '0x0000000000000000000000000000000000000000' - -enum ActionType { - OpenVault, - MintShortOption, - BurnShortOption, - DepositLongOption, - WithdrawLongOption, - DepositCollateral, - WithdrawCollateral, - SettleVault, - Redeem, - Call, -} - -contract('Naked Call Option expires Itm flow', ([accountOwner1, buyer]) => { - let expiry: number - - let addressBook: AddressBookInstance - let calculator: MarginCalculatorInstance - let controllerProxy: ControllerInstance - let controllerImplementation: ControllerInstance - let marginPool: MarginPoolInstance - let borrowableMarginPool: BorrowableMarginPoolInstance - let whitelist: WhitelistInstance - let otokenImplementation: OtokenInstance - let otokenFactory: OtokenFactoryInstance - - // oracle modulce mock - let oracle: MockOracleInstance - - let usdc: MockERC20Instance - let weth: MockERC20Instance - - let ethCall: OtokenInstance - const strikePrice = 300 - - const optionsAmount = 10 - const collateralAmount = optionsAmount - let vaultCounter: number - - const usdcDecimals = 6 - const wethDecimals = 18 - - before('set up contracts', async () => { - const now = (await time.latest()).toNumber() - expiry = createValidExpiry(now, 30) - - // setup usdc and weth - usdc = await MockERC20.new('USDC', 'USDC', usdcDecimals) - weth = await MockERC20.new('WETH', 'WETH', wethDecimals) - // initiate addressbook first. - addressBook = await AddressBook.new() - // setup margin pool - marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) - // setup margin vault - const lib = await MarginVault.new() - // setup controllerProxy module - await Controller.link('MarginVault', lib.address) - controllerImplementation = await Controller.new(addressBook.address) - // setup mock Oracle module - oracle = await MockOracle.new(addressBook.address) - // setup calculator - calculator = await MarginCalculator.new(oracle.address) - // setup whitelist module - whitelist = await Whitelist.new(addressBook.address) - await whitelist.whitelistCollateral(weth.address) - await whitelist.whitelistCollateral(usdc.address) - whitelist.whitelistProduct(weth.address, usdc.address, usdc.address, true) - whitelist.whitelistProduct(weth.address, usdc.address, weth.address, false) - // setup otoken - otokenImplementation = await Otoken.new() - // setup factory - otokenFactory = await OTokenFactory.new(addressBook.address) - - // setup address book - await addressBook.setOracle(oracle.address) - await addressBook.setMarginCalculator(calculator.address) - await addressBook.setWhitelist(whitelist.address) - await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) - await addressBook.setOtokenFactory(otokenFactory.address) - await addressBook.setOtokenImpl(otokenImplementation.address) - await addressBook.setController(controllerImplementation.address) - - const controllerProxyAddress = await addressBook.getController() - controllerProxy = await Controller.at(controllerProxyAddress) - - await otokenFactory.createOtoken( - weth.address, - usdc.address, - weth.address, - createTokenAmount(strikePrice), - expiry, - false, - ) - - const ethCallAddress = await otokenFactory.getOtoken( - weth.address, - usdc.address, - weth.address, - createTokenAmount(strikePrice), - expiry, - false, - ) - - ethCall = await Otoken.at(ethCallAddress) - // mint weth to user - const account1OwnerWeth = createTokenAmount(2 * collateralAmount, wethDecimals) - await weth.mint(accountOwner1, account1OwnerWeth) - - // have the user approve all the weth transfers - await weth.approve(borrowableMarginPool.address, account1OwnerWeth, { from: accountOwner1 }) - - const vaultCounterBefore = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - vaultCounter = vaultCounterBefore.toNumber() + 1 - - await borrowableMarginPool.setOptionsVaultWhitelistedStatus(accountOwner1, true, { from: accountOwner1 }) - await borrowableMarginPool.setOTokenBuyerWhitelistedStatus(buyer, true, { from: accountOwner1 }) - }) - - describe('Integration test: Close a naked call after it expires ITM', () => { - const scaledOptionsAmount = createTokenAmount(optionsAmount) - const scaledCollateralAmount = createTokenAmount(collateralAmount, wethDecimals) - const expirySpotPrice = 400 - before('Seller should be able to open a short call option', async () => { - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ethCall.address, - vaultId: vaultCounter, - amount: scaledOptionsAmount, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: weth.address, - vaultId: vaultCounter, - amount: scaledCollateralAmount, - index: '0', - data: ZERO_ADDR, - }, - ] - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - }) - - it('Seller: close an ITM position after expiry', async () => { - // Keep track of balances before - const ownerWethBalanceBefore = new BigNumber(await weth.balanceOf(accountOwner1)) - const borrowableMarginPoolWethBalanceBefore = new BigNumber(await weth.balanceOf(borrowableMarginPool.address)) - const ownerOtokenBalanceBefore = new BigNumber(await ethCall.balanceOf(accountOwner1)) - const oTokenSupplyBefore = new BigNumber(await ethCall.totalSupply()) - - // Check that we start at a valid state - const vaultBefore = await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter) - const vaultStateBefore = await calculator.getExcessCollateral(vaultBefore[0], vaultBefore[1]) - assert.equal(vaultStateBefore[0].toString(), '0') - assert.equal(vaultStateBefore[1], true) - - // Set the oracle price - if ((await time.latest()) < expiry) { - await time.increaseTo(expiry + 2) - } - const strikePriceChange = Math.max(expirySpotPrice - strikePrice, 0) - const scaledETHPrice = createTokenAmount(expirySpotPrice, 8) - const scaledUSDCPrice = createTokenAmount(1) - await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry, scaledETHPrice, true) - await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, scaledUSDCPrice, true) - - const collateralPayout = collateralAmount - (strikePriceChange * optionsAmount) / expirySpotPrice - - // Check that after expiry, the vault excess balance has updated as expected - const vaultStateBeforeSettlement = await calculator.getExcessCollateral(vaultBefore[0], vaultBefore[1]) - assert.equal( - vaultStateBeforeSettlement[0].toString(), - createTokenAmount(collateralPayout, wethDecimals), - 'vault before settlement collateral excess mismatch', - ) - assert.equal(vaultStateBeforeSettlement[1], true) - - const actionArgs = [ - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - // keep track of balances after - const ownerWethBalanceAfter = new BigNumber(await weth.balanceOf(accountOwner1)) - const borrowableMarginPoolWethBalanceAfter = new BigNumber(await weth.balanceOf(borrowableMarginPool.address)) - - const ownerOtokenBalanceAfter = new BigNumber(await ethCall.balanceOf(accountOwner1)) - const oTokenSupplyAfter = new BigNumber(await ethCall.totalSupply()) - - // check balances before and after changed as expected - assert.equal( - ownerWethBalanceBefore.plus(createTokenAmount(collateralPayout, wethDecimals)).toString(), - ownerWethBalanceAfter.toString(), - ) - assert.equal( - borrowableMarginPoolWethBalanceBefore.minus(createTokenAmount(collateralPayout, wethDecimals)).toString(), - borrowableMarginPoolWethBalanceAfter.toString(), - ) - assert.equal(ownerOtokenBalanceBefore.toString(), ownerOtokenBalanceAfter.toString()) - assert.equal(oTokenSupplyBefore.toString(), oTokenSupplyAfter.toString()) - - // Check that we end at a valid state - const vaultAfter = await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter) - const vaultStateAfter = await calculator.getExcessCollateral(vaultAfter[0], vaultAfter[1]) - assert.equal(vaultStateAfter[0].toString(), '0') - assert.equal(vaultStateAfter[1], true) - - // Check the vault balances stored in the contract - assert.equal(vaultAfter[0].shortOtokens.length, 0, 'Length of the short otoken array in the vault is incorrect') - assert.equal(vaultAfter[0].collateralAssets.length, 0, 'Length of the collateral array in the vault is incorrect') - assert.equal(vaultAfter[0].longOtokens.length, 0, 'Length of the long otoken array in the vault is incorrect') - - assert.equal(vaultAfter[0].shortAmounts.length, 0, 'Length of the short amounts array in the vault is incorrect') - assert.equal( - vaultAfter[0].collateralAmounts.length, - 0, - 'Length of the collateral amounts array in the vault is incorrect', - ) - assert.equal(vaultAfter[0].longAmounts.length, 0, 'Length of the long amounts array in the vault is incorrect') - }) - - it('Buyer: redeem ITM call option after expiry', async () => { - // owner sells their call option - await ethCall.transfer(buyer, scaledOptionsAmount, { from: accountOwner1 }) - // oracle orice increases - const strikePriceChange = Math.max(expirySpotPrice - strikePrice, 0) - - // Keep track of balances before - const ownerWethBalanceBefore = new BigNumber(await weth.balanceOf(buyer)) - const borrowableMarginPoolWethBalanceBefore = new BigNumber(await weth.balanceOf(borrowableMarginPool.address)) - const ownerOtokenBalanceBefore = new BigNumber(await ethCall.balanceOf(buyer)) - const oTokenSupplyBefore = new BigNumber(await ethCall.totalSupply()) - - const actionArgs = [ - { - actionType: ActionType.Redeem, - owner: buyer, - secondAddress: buyer, - asset: ethCall.address, - vaultId: '0', - amount: scaledOptionsAmount, - index: '0', - data: ZERO_ADDR, - }, - ] - - await controllerProxy.operate(actionArgs, { from: buyer }) - - // keep track of balances after - const ownerWethBalanceAfter = new BigNumber(await weth.balanceOf(buyer)) - const borrowableMarginPoolWethBalanceAfter = new BigNumber(await weth.balanceOf(borrowableMarginPool.address)) - const ownerOtokenBalanceAfter = new BigNumber(await ethCall.balanceOf(buyer)) - const oTokenSupplyAfter = new BigNumber(await ethCall.totalSupply()) - - const payout = (strikePriceChange * optionsAmount) / expirySpotPrice - const scaledPayout = createTokenAmount(payout, wethDecimals) - - // check balances before and after changed as expected - assert.equal(ownerWethBalanceBefore.plus(scaledPayout).toString(), ownerWethBalanceAfter.toString()) - assert.equal( - borrowableMarginPoolWethBalanceBefore.minus(scaledPayout).toString(), - borrowableMarginPoolWethBalanceAfter.toString(), - ) - assert.equal(ownerOtokenBalanceBefore.minus(scaledOptionsAmount).toString(), ownerOtokenBalanceAfter.toString()) - assert.equal(oTokenSupplyBefore.minus(scaledOptionsAmount).toString(), oTokenSupplyAfter.toString()) - }) - }) -}) diff --git a/test/integration-tests/nakedCallExpireItm.test.ts b/test/integration-tests/nakedCallExpireItm.test.ts index 8a8301cfc..5447bab44 100644 --- a/test/integration-tests/nakedCallExpireItm.test.ts +++ b/test/integration-tests/nakedCallExpireItm.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Naked Call Option expires Itm flow', ([accountOwner1, buyer]) => { let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -80,8 +77,6 @@ contract('Naked Call Option expires Itm flow', ([accountOwner1, buyer]) => { addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -107,9 +102,6 @@ contract('Naked Call Option expires Itm flow', ([accountOwner1, buyer]) => { await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/nakedCallExpireOtm-borrowableMarginPool.test.ts b/test/integration-tests/nakedCallExpireOtm-borrowableMarginPool.test.ts deleted file mode 100644 index a05237d42..000000000 --- a/test/integration-tests/nakedCallExpireOtm-borrowableMarginPool.test.ts +++ /dev/null @@ -1,310 +0,0 @@ -import { - MockERC20Instance, - MarginCalculatorInstance, - AddressBookInstance, - MockOracleInstance, - OtokenInstance, - ControllerInstance, - WhitelistInstance, - MarginPoolInstance, - BorrowableMarginPoolInstance, - OtokenFactoryInstance, -} from '../../build/types/truffle-types' -import { createTokenAmount, createValidExpiry } from '../utils' -import BigNumber from 'bignumber.js' - -const { time } = require('@openzeppelin/test-helpers') -const AddressBook = artifacts.require('AddressBook.sol') -const MockOracle = artifacts.require('MockOracle.sol') -const Otoken = artifacts.require('Otoken.sol') -const MockERC20 = artifacts.require('MockERC20.sol') -const MarginCalculator = artifacts.require('MarginCalculator.sol') -const Whitelist = artifacts.require('Whitelist.sol') -const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') -const Controller = artifacts.require('Controller.sol') -const MarginVault = artifacts.require('MarginVault.sol') -const OTokenFactory = artifacts.require('OtokenFactory.sol') -const ZERO_ADDR = '0x0000000000000000000000000000000000000000' - -enum ActionType { - OpenVault, - MintShortOption, - BurnShortOption, - DepositLongOption, - WithdrawLongOption, - DepositCollateral, - WithdrawCollateral, - SettleVault, - Redeem, - Call, -} - -contract('Naked Call Option expires Otm flow', ([accountOwner1, buyer]) => { - let expiry: number - - let addressBook: AddressBookInstance - let calculator: MarginCalculatorInstance - let controllerProxy: ControllerInstance - let controllerImplementation: ControllerInstance - let marginPool: MarginPoolInstance - let borrowableMarginPool: BorrowableMarginPoolInstance - let whitelist: WhitelistInstance - let otokenImplementation: OtokenInstance - let otokenFactory: OtokenFactoryInstance - - // oracle modulce mock - let oracle: MockOracleInstance - - let usdc: MockERC20Instance - let weth: MockERC20Instance - - let ethCall: OtokenInstance - const strikePrice = 300 - - const optionsAmount = 10 - const collateralAmount = optionsAmount - let vaultCounter: number - - const usdcDecimals = 6 - const wethDecimals = 18 - - before('set up contracts', async () => { - const now = (await time.latest()).toNumber() - expiry = createValidExpiry(now, 30) - - // setup usdc and weth - usdc = await MockERC20.new('USDC', 'USDC', usdcDecimals) - weth = await MockERC20.new('WETH', 'WETH', wethDecimals) - - // initiate addressbook first. - addressBook = await AddressBook.new() - // setup margin pool - marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) - // setup margin vault - const lib = await MarginVault.new() - // setup controllerProxy module - await Controller.link('MarginVault', lib.address) - controllerImplementation = await Controller.new(addressBook.address) - // setup mock Oracle module - oracle = await MockOracle.new(addressBook.address) - // setup calculator - calculator = await MarginCalculator.new(oracle.address) - // setup whitelist module - whitelist = await Whitelist.new(addressBook.address) - await whitelist.whitelistCollateral(weth.address) - await whitelist.whitelistCollateral(usdc.address) - whitelist.whitelistProduct(weth.address, usdc.address, usdc.address, true) - whitelist.whitelistProduct(weth.address, usdc.address, weth.address, false) - // setup otoken - otokenImplementation = await Otoken.new() - // setup factory - otokenFactory = await OTokenFactory.new(addressBook.address) - - // setup address book - await addressBook.setOracle(oracle.address) - await addressBook.setMarginCalculator(calculator.address) - await addressBook.setWhitelist(whitelist.address) - await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) - await addressBook.setOtokenFactory(otokenFactory.address) - await addressBook.setOtokenImpl(otokenImplementation.address) - await addressBook.setController(controllerImplementation.address) - - const controllerProxyAddress = await addressBook.getController() - controllerProxy = await Controller.at(controllerProxyAddress) - - await otokenFactory.createOtoken( - weth.address, - usdc.address, - weth.address, - createTokenAmount(strikePrice), - expiry, - false, - ) - - const ethCallAddress = await otokenFactory.getOtoken( - weth.address, - usdc.address, - weth.address, - createTokenAmount(strikePrice), - expiry, - false, - ) - - ethCall = await Otoken.at(ethCallAddress) - // mint weth to user - const account1OwnerWeth = createTokenAmount(2 * collateralAmount, wethDecimals) - await weth.mint(accountOwner1, account1OwnerWeth) - - // have the user approve all the weth transfers - await weth.approve(borrowableMarginPool.address, account1OwnerWeth, { from: accountOwner1 }) - - const vaultCounterBefore = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - vaultCounter = vaultCounterBefore.toNumber() + 1 - - await borrowableMarginPool.setOptionsVaultWhitelistedStatus(accountOwner1, true, { from: accountOwner1 }) - }) - - describe('Close a naked call after it expires OTM', () => { - const scaledOptionsAmount = createTokenAmount(optionsAmount, 8) - const scaledCollateralAmount = createTokenAmount(collateralAmount, wethDecimals) - const expirySpotPrice = 200 - before('Seller should be able to open a short call option', async () => { - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ethCall.address, - vaultId: vaultCounter, - amount: scaledOptionsAmount, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: weth.address, - vaultId: vaultCounter, - amount: scaledCollateralAmount, - index: '0', - data: ZERO_ADDR, - }, - ] - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - }) - - it('Seller: close an OTM position after expiry', async () => { - // Keep track of balances before - const ownerWethBalanceBefore = new BigNumber(await weth.balanceOf(accountOwner1)) - const borrowableMarginPoolWethBalanceBefore = new BigNumber(await weth.balanceOf(borrowableMarginPool.address)) - const ownerOtokenBalanceBefore = new BigNumber(await ethCall.balanceOf(accountOwner1)) - const oTokenSupplyBefore = new BigNumber(await ethCall.totalSupply()) - - // Check that we start at a valid state - const vaultBefore = await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter) - const vaultStateBefore = await calculator.getExcessCollateral(vaultBefore[0], vaultBefore[1]) - assert.equal(vaultStateBefore[0].toString(), '0') - assert.equal(vaultStateBefore[1], true) - - // Set the oracle price - if ((await time.latest()) < expiry) { - await time.increaseTo(expiry + 2) - } - const scaledETHPrice = createTokenAmount(expirySpotPrice, 8) - const scaledUSDCPrice = createTokenAmount(1) - await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry, scaledETHPrice, true) - await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, scaledUSDCPrice, true) - - // Check that after expiry, the vault excess balance has updated as expected - const vaultStateBeforeSettlement = await calculator.getExcessCollateral(vaultBefore[0], vaultBefore[1]) - assert.equal(vaultStateBeforeSettlement[0].toString(), scaledCollateralAmount) - assert.equal(vaultStateBeforeSettlement[1], true) - - const actionArgs = [ - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - // keep track of balances after - const ownerWethBalanceAfter = new BigNumber(await weth.balanceOf(accountOwner1)) - const borrowableMarginPoolWethBalanceAfter = new BigNumber(await weth.balanceOf(borrowableMarginPool.address)) - - const ownerOtokenBalanceAfter = new BigNumber(await ethCall.balanceOf(accountOwner1)) - const oTokenSupplyAfter = new BigNumber(await ethCall.totalSupply()) - - // check balances before and after changed as expected - assert.equal(ownerWethBalanceBefore.plus(scaledCollateralAmount).toString(), ownerWethBalanceAfter.toString()) - assert.equal( - borrowableMarginPoolWethBalanceBefore.minus(scaledCollateralAmount).toString(), - borrowableMarginPoolWethBalanceAfter.toString(), - ) - assert.equal(ownerOtokenBalanceBefore.toString(), ownerOtokenBalanceAfter.toString()) - assert.equal(oTokenSupplyBefore.toString(), oTokenSupplyAfter.toString()) - - // Check that we end at a valid state - const vaultAfter = await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter) - const vaultStateAfter = await calculator.getExcessCollateral(vaultAfter[0], vaultBefore[1]) - assert.equal(vaultStateAfter[0].toString(), '0') - assert.equal(vaultStateAfter[1], true) - - // Check the vault balances stored in the contract - assert.equal(vaultAfter[0].shortOtokens.length, 0, 'Length of the short otoken array in the vault is incorrect') - assert.equal(vaultAfter[0].collateralAssets.length, 0, 'Length of the collateral array in the vault is incorrect') - assert.equal(vaultAfter[0].longOtokens.length, 0, 'Length of the long otoken array in the vault is incorrect') - - assert.equal(vaultAfter[0].shortAmounts.length, 0, 'Length of the short amounts array in the vault is incorrect') - assert.equal( - vaultAfter[0].collateralAmounts.length, - 0, - 'Length of the collateral amounts array in the vault is incorrect', - ) - assert.equal(vaultAfter[0].longAmounts.length, 0, 'Length of the long amounts array in the vault is incorrect') - }) - - it('Buyer: redeem OTM call option after expiry', async () => { - // owner sells their call option - await ethCall.transfer(buyer, scaledOptionsAmount, { from: accountOwner1 }) - - // Keep track of balances before - const ownerWethBalanceBefore = new BigNumber(await weth.balanceOf(buyer)) - const borrowableMarginPoolWethBalanceBefore = new BigNumber(await weth.balanceOf(borrowableMarginPool.address)) - const ownerOtokenBalanceBefore = new BigNumber(await ethCall.balanceOf(buyer)) - const oTokenSupplyBefore = new BigNumber(await ethCall.totalSupply()) - - const actionArgs = [ - { - actionType: ActionType.Redeem, - owner: buyer, - secondAddress: buyer, - asset: ethCall.address, - vaultId: '0', - amount: scaledOptionsAmount, - index: '0', - data: ZERO_ADDR, - }, - ] - - await controllerProxy.operate(actionArgs, { from: buyer }) - - // keep track of balances after - const ownerWethBalanceAfter = new BigNumber(await weth.balanceOf(buyer)) - const borrowableMarginPoolWethBalanceAfter = new BigNumber(await weth.balanceOf(borrowableMarginPool.address)) - const ownerOtokenBalanceAfter = new BigNumber(await ethCall.balanceOf(buyer)) - const oTokenSupplyAfter = new BigNumber(await ethCall.totalSupply()) - - // check balances before and after changed as expected - assert.equal(ownerWethBalanceBefore.toString(), ownerWethBalanceAfter.toString()) - assert.equal(borrowableMarginPoolWethBalanceBefore.toString(), borrowableMarginPoolWethBalanceAfter.toString()) - assert.equal(ownerOtokenBalanceBefore.minus(scaledOptionsAmount).toString(), ownerOtokenBalanceAfter.toString()) - assert.equal(oTokenSupplyBefore.minus(scaledOptionsAmount).toString(), oTokenSupplyAfter.toString()) - }) - }) -}) diff --git a/test/integration-tests/nakedCallExpireOtm.test.ts b/test/integration-tests/nakedCallExpireOtm.test.ts index af1e0d83a..eaa1b3cd6 100644 --- a/test/integration-tests/nakedCallExpireOtm.test.ts +++ b/test/integration-tests/nakedCallExpireOtm.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Naked Call Option expires Otm flow', ([accountOwner1, buyer]) => { let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -81,8 +78,6 @@ contract('Naked Call Option expires Otm flow', ([accountOwner1, buyer]) => { addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -108,9 +103,6 @@ contract('Naked Call Option expires Otm flow', ([accountOwner1, buyer]) => { await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/nakedCallPreExpiry-borrowableMarginPool.test.ts b/test/integration-tests/nakedCallPreExpiry-borrowableMarginPool.test.ts deleted file mode 100644 index 6c41511e3..000000000 --- a/test/integration-tests/nakedCallPreExpiry-borrowableMarginPool.test.ts +++ /dev/null @@ -1,355 +0,0 @@ -import { - MockERC20Instance, - MarginCalculatorInstance, - AddressBookInstance, - MockOracleInstance, - OtokenInstance, - ControllerInstance, - WhitelistInstance, - MarginPoolInstance, - BorrowableMarginPoolInstance, - OtokenFactoryInstance, -} from '../../build/types/truffle-types' -import { createTokenAmount, createValidExpiry } from '../utils' -import BigNumber from 'bignumber.js' - -const { time } = require('@openzeppelin/test-helpers') -const AddressBook = artifacts.require('AddressBook.sol') -const MockOracle = artifacts.require('MockOracle.sol') -const Otoken = artifacts.require('Otoken.sol') -const MockERC20 = artifacts.require('MockERC20.sol') -const MarginCalculator = artifacts.require('MarginCalculator.sol') -const Whitelist = artifacts.require('Whitelist.sol') -const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') -const Controller = artifacts.require('Controller.sol') -const MarginVault = artifacts.require('MarginVault.sol') -const OTokenFactory = artifacts.require('OtokenFactory.sol') -const ZERO_ADDR = '0x0000000000000000000000000000000000000000' - -enum ActionType { - OpenVault, - MintShortOption, - BurnShortOption, - DepositLongOption, - WithdrawLongOption, - DepositCollateral, - WithdrawCollateral, - SettleVault, - Redeem, - Call, -} - -contract('Naked Call Option closed before expiry flow', ([accountOwner1]) => { - let expiry: number - - let addressBook: AddressBookInstance - let calculator: MarginCalculatorInstance - let controllerProxy: ControllerInstance - let controllerImplementation: ControllerInstance - let marginPool: MarginPoolInstance - let borrowableMarginPool: BorrowableMarginPoolInstance - let whitelist: WhitelistInstance - let otokenImplementation: OtokenInstance - let otokenFactory: OtokenFactoryInstance - - // oracle modulce mock - let oracle: MockOracleInstance - - let usdc: MockERC20Instance - let weth: MockERC20Instance - - let ethCall: OtokenInstance - const strikePrice = 300 - - const optionsAmount = 10 - const collateralAmount = optionsAmount - let vaultCounter: number - - const usdcDecimals = 6 - const wethDecimals = 18 - - before('set up contracts', async () => { - const now = (await time.latest()).toNumber() - expiry = createValidExpiry(now, 30) - - // setup usdc and weth - usdc = await MockERC20.new('USDC', 'USDC', usdcDecimals) - weth = await MockERC20.new('WETH', 'WETH', wethDecimals) - - // initiate addressbook first. - addressBook = await AddressBook.new() - // setup margin pool - marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) - // setup margin vault - const lib = await MarginVault.new() - // setup controllerProxy module - await Controller.link('MarginVault', lib.address) - controllerImplementation = await Controller.new(addressBook.address) - // setup mock Oracle module - oracle = await MockOracle.new(addressBook.address) - // setup calculator - calculator = await MarginCalculator.new(oracle.address) - // setup whitelist module - whitelist = await Whitelist.new(addressBook.address) - await whitelist.whitelistCollateral(weth.address) - await whitelist.whitelistCollateral(usdc.address) - whitelist.whitelistProduct(weth.address, usdc.address, usdc.address, true) - whitelist.whitelistProduct(weth.address, usdc.address, weth.address, false) - // setup otoken - otokenImplementation = await Otoken.new() - // setup factory - otokenFactory = await OTokenFactory.new(addressBook.address) - - // setup address book - await addressBook.setOracle(oracle.address) - await addressBook.setMarginCalculator(calculator.address) - await addressBook.setWhitelist(whitelist.address) - await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) - await addressBook.setOtokenFactory(otokenFactory.address) - await addressBook.setOtokenImpl(otokenImplementation.address) - await addressBook.setController(controllerImplementation.address) - - const controllerProxyAddress = await addressBook.getController() - controllerProxy = await Controller.at(controllerProxyAddress) - - await otokenFactory.createOtoken( - weth.address, - usdc.address, - weth.address, - createTokenAmount(strikePrice), - expiry, - false, - ) - - const ethCallAddress = await otokenFactory.getOtoken( - weth.address, - usdc.address, - weth.address, - createTokenAmount(strikePrice), - expiry, - false, - ) - - ethCall = await Otoken.at(ethCallAddress) - // mint weth to user - const account1OwnerWeth = createTokenAmount(2 * collateralAmount, wethDecimals) - await weth.mint(accountOwner1, account1OwnerWeth) - - // have the user approve all the weth transfers - await weth.approve(borrowableMarginPool.address, account1OwnerWeth, { from: accountOwner1 }) - - const vaultCounterBefore = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - vaultCounter = vaultCounterBefore.toNumber() + 1 - - await borrowableMarginPool.setOptionsVaultWhitelistedStatus(accountOwner1, true, { from: accountOwner1 }) - }) - - describe('Integration test: Sell a naked call and close it before expiry', () => { - const scaledOptionsAmount = createTokenAmount(optionsAmount, 8) - const scaledCollateralAmount = createTokenAmount(collateralAmount, wethDecimals) - it('Seller should be able to open a short call option', async () => { - // Keep track of balances before - const ownerWethBalanceBefore = new BigNumber(await weth.balanceOf(accountOwner1)) - const borrowableMarginPoolWethBalanceBefore = new BigNumber(await weth.balanceOf(borrowableMarginPool.address)) - const ownerOtokenBalanceBefore = new BigNumber(await ethCall.balanceOf(accountOwner1)) - const oTokenSupplyBefore = new BigNumber(await ethCall.totalSupply()) - - // Check that we start at a valid state - const vaultBefore = await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter) - const vaultStateBefore = await calculator.getExcessCollateral(vaultBefore[0], vaultBefore[1]) - assert.equal(vaultStateBefore[0].toString(), '0') - assert.equal(vaultStateBefore[1], true) - - // Check the vault balances stored in the contract - assert.equal(vaultBefore[0].shortOtokens.length, 0, 'Length of the short otoken array in the vault is incorrect') - assert.equal( - vaultBefore[0].collateralAssets.length, - 0, - 'Length of the collateral array in the vault is incorrect', - ) - assert.equal(vaultBefore[0].longOtokens.length, 0, 'Length of the long otoken array in the vault is incorrect') - - assert.equal(vaultBefore[0].shortAmounts.length, 0, 'Length of the short amounts array in the vault is incorrect') - assert.equal( - vaultBefore[0].collateralAmounts.length, - 0, - 'Length of the collateral amounts array in the vault is incorrect', - ) - assert.equal(vaultBefore[0].longAmounts.length, 0, 'Length of the long amounts array in the vault is incorrect') - - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ethCall.address, - vaultId: vaultCounter, - amount: scaledOptionsAmount, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: weth.address, - vaultId: vaultCounter, - amount: scaledCollateralAmount, - index: '0', - data: ZERO_ADDR, - }, - ] - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - // keep track of balances after - const ownerWethBalanceAfter = new BigNumber(await weth.balanceOf(accountOwner1)) - const borrowableMarginPoolWethBalanceAfter = new BigNumber(await weth.balanceOf(borrowableMarginPool.address)) - - const ownerOtokenBalanceAfter = new BigNumber(await ethCall.balanceOf(accountOwner1)) - const oTokenSupplyAfter = new BigNumber(await ethCall.totalSupply()) - - // check balances before and after changed as expected - assert.equal(ownerWethBalanceBefore.minus(scaledCollateralAmount).toString(), ownerWethBalanceAfter.toString()) - assert.equal( - borrowableMarginPoolWethBalanceBefore.plus(scaledCollateralAmount).toString(), - borrowableMarginPoolWethBalanceAfter.toString(), - ) - assert.equal(ownerOtokenBalanceBefore.plus(scaledOptionsAmount).toString(), ownerOtokenBalanceAfter.toString()) - assert.equal(oTokenSupplyBefore.plus(scaledOptionsAmount).toString(), oTokenSupplyAfter.toString()) - - // Check that we end at a valid state - const vaultAfter = await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter) - const vaultStateAfter = await calculator.getExcessCollateral(vaultAfter[0], vaultAfter[1]) - assert.equal(vaultStateAfter[0].toString(), '0') - assert.equal(vaultStateAfter[1], true) - - // Check the vault balances stored in the contract - assert.equal(vaultAfter[0].shortOtokens.length, 1, 'Length of the short otoken array in the vault is incorrect') - assert.equal(vaultAfter[0].collateralAssets.length, 1, 'Length of the collateral array in the vault is incorrect') - assert.equal(vaultAfter[0].longOtokens.length, 0, 'Length of the long otoken array in the vault is incorrect') - - assert.equal(vaultAfter[0].shortOtokens[0], ethCall.address, 'Incorrect short otoken in the vault') - assert.equal(vaultAfter[0].collateralAssets[0], weth.address, 'Incorrect collateral asset in the vault') - - assert.equal(vaultAfter[0].shortAmounts.length, 1, 'Length of the short amounts array in the vault is incorrect') - assert.equal( - vaultAfter[0].collateralAmounts.length, - 1, - 'Length of the collateral amounts array in the vault is incorrect', - ) - assert.equal(vaultAfter[0].longAmounts.length, 0, 'Length of the long amounts array in the vault is incorrect') - - assert.equal( - vaultAfter[0].shortAmounts[0].toString(), - scaledOptionsAmount, - 'Incorrect amount of short stored in the vault', - ) - assert.equal( - vaultAfter[0].collateralAmounts[0].toString(), - scaledCollateralAmount, - 'Incorrect amount of collateral stored in the vault', - ) - }) - - it('should be able to close out the short position', async () => { - // Keep track of balances before - const ownerWethBalanceBefore = new BigNumber(await weth.balanceOf(accountOwner1)) - const borrowableMarginPoolWethBalanceBefore = new BigNumber(await weth.balanceOf(borrowableMarginPool.address)) - const ownerOtokenBalanceBefore = new BigNumber(await ethCall.balanceOf(accountOwner1)) - const oTokenSupplyBefore = new BigNumber(await ethCall.totalSupply()) - - // Check that we start at a valid state - const vaultBefore = await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter) - const vaultStateBefore = await calculator.getExcessCollateral(vaultBefore[0], vaultBefore[1]) - assert.equal(vaultStateBefore[0].toString(), '0') - assert.equal(vaultStateBefore[1], true) - - const actionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: weth.address, - vaultId: vaultCounter, - amount: scaledCollateralAmount, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.BurnShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ethCall.address, - vaultId: vaultCounter, - amount: scaledOptionsAmount, - index: '0', - data: ZERO_ADDR, - }, - ] - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - // keep track of balances after - const ownerWethBalanceAfter = new BigNumber(await weth.balanceOf(accountOwner1)) - const borrowableMarginPoolWethBalanceAfter = new BigNumber(await weth.balanceOf(borrowableMarginPool.address)) - - const ownerOtokenBalanceAfter = new BigNumber(await ethCall.balanceOf(accountOwner1)) - const oTokenSupplyAfter = new BigNumber(await ethCall.totalSupply()) - - // check balances before and after changed as expected - assert.equal(ownerWethBalanceBefore.plus(scaledCollateralAmount).toString(), ownerWethBalanceAfter.toString()) - assert.equal( - borrowableMarginPoolWethBalanceBefore.minus(scaledCollateralAmount).toString(), - borrowableMarginPoolWethBalanceAfter.toString(), - ) - assert.equal(ownerOtokenBalanceBefore.minus(scaledOptionsAmount).toString(), ownerOtokenBalanceAfter.toString()) - assert.equal(oTokenSupplyBefore.minus(scaledOptionsAmount).toString(), oTokenSupplyAfter.toString()) - - // Check that we end at a valid state - const vaultAfter = await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter) - const vaultStateAfter = await calculator.getExcessCollateral(vaultAfter[0], vaultAfter[1]) - assert.equal(vaultStateAfter[0].toString(), '0') - assert.equal(vaultStateAfter[1], true) - - // Check the vault balances stored in the contract - assert.equal(vaultAfter[0].shortOtokens.length, 1, 'Length of the short otoken array in the vault is incorrect') - assert.equal(vaultAfter[0].collateralAssets.length, 1, 'Length of the collateral array in the vault is incorrect') - assert.equal(vaultAfter[0].longOtokens.length, 0, 'Length of the long otoken array in the vault is incorrect') - - assert.equal(vaultAfter[0].shortOtokens[0], ZERO_ADDR, 'Incorrect short otoken in the vault') - assert.equal(vaultAfter[0].collateralAssets[0], ZERO_ADDR, 'Incorrect collateral asset in the vault') - - assert.equal(vaultAfter[0].shortAmounts.length, 1, 'Length of the short amounts array in the vault is incorrect') - assert.equal( - vaultAfter[0].collateralAmounts.length, - 1, - 'Length of the collateral amounts array in the vault is incorrect', - ) - assert.equal(vaultAfter[0].longAmounts.length, 0, 'Length of the long amounts array in the vault is incorrect') - - assert.equal(vaultAfter[0].shortAmounts[0].toString(), '0', 'Incorrect amount of short stored in the vault') - assert.equal( - vaultAfter[0].collateralAmounts[0].toString(), - '0', - 'Incorrect amount of collateral stored in the vault', - ) - }) - }) -}) diff --git a/test/integration-tests/nakedCallPreExpiry.test.ts b/test/integration-tests/nakedCallPreExpiry.test.ts index d5a810a05..dc3879b85 100644 --- a/test/integration-tests/nakedCallPreExpiry.test.ts +++ b/test/integration-tests/nakedCallPreExpiry.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Naked Call Option closed before expiry flow', ([accountOwner1]) => { let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -81,8 +78,6 @@ contract('Naked Call Option closed before expiry flow', ([accountOwner1]) => { addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -108,9 +103,6 @@ contract('Naked Call Option closed before expiry flow', ([accountOwner1]) => { await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/nakedMarginCallPreExpiry.test.ts b/test/integration-tests/nakedMarginCallPreExpiry.test.ts index 00c5fa672..04ae8b21b 100644 --- a/test/integration-tests/nakedMarginCallPreExpiry.test.ts +++ b/test/integration-tests/nakedMarginCallPreExpiry.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { @@ -28,7 +27,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -78,7 +76,6 @@ contract('Naked margin: call position pre expiry', ([owner, accountOwner1, liqui let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -98,8 +95,6 @@ contract('Naked margin: call position pre expiry', ([owner, accountOwner1, liqui addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -126,9 +121,6 @@ contract('Naked margin: call position pre expiry', ([owner, accountOwner1, liqui await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: owner, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/nakedMarginPutPreExpiry.test.ts b/test/integration-tests/nakedMarginPutPreExpiry.test.ts index 82faf806b..c3f4b2149 100644 --- a/test/integration-tests/nakedMarginPutPreExpiry.test.ts +++ b/test/integration-tests/nakedMarginPutPreExpiry.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { @@ -28,7 +27,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -78,7 +76,6 @@ contract('Naked margin: put position pre expiry', ([owner, accountOwner1, buyer1 let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -98,8 +95,6 @@ contract('Naked margin: put position pre expiry', ([owner, accountOwner1, buyer1 addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -126,9 +121,6 @@ contract('Naked margin: put position pre expiry', ([owner, accountOwner1, buyer1 await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: owner, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/nakedPutExpireITM.test.ts b/test/integration-tests/nakedPutExpireITM.test.ts index ee2e406b6..4329af730 100644 --- a/test/integration-tests/nakedPutExpireITM.test.ts +++ b/test/integration-tests/nakedPutExpireITM.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Naked Put Option expires Itm flow', ([accountOwner1, buyer]) => { let controllerImplementation: ControllerInstance let controllerProxy: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -81,8 +78,6 @@ contract('Naked Put Option expires Itm flow', ([accountOwner1, buyer]) => { addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controller module @@ -108,9 +103,6 @@ contract('Naked Put Option expires Itm flow', ([accountOwner1, buyer]) => { await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/nakedPutExpireOTM.test.ts b/test/integration-tests/nakedPutExpireOTM.test.ts index 013cbbb5c..4dc1cf4b4 100644 --- a/test/integration-tests/nakedPutExpireOTM.test.ts +++ b/test/integration-tests/nakedPutExpireOTM.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Naked Put Option expires Otm flow', ([accountOwner1, buyer]) => { let controllerImplementation: ControllerInstance let controllerProxy: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -81,8 +78,6 @@ contract('Naked Put Option expires Otm flow', ([accountOwner1, buyer]) => { addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controller module @@ -108,9 +103,6 @@ contract('Naked Put Option expires Otm flow', ([accountOwner1, buyer]) => { await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/nakedPutPreExpiry.test.ts b/test/integration-tests/nakedPutPreExpiry.test.ts index 91a5eca9c..d9923637f 100644 --- a/test/integration-tests/nakedPutPreExpiry.test.ts +++ b/test/integration-tests/nakedPutPreExpiry.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Naked Put Option closed before expiry flow', ([accountOwner1]) => { let controllerImplementation: ControllerInstance let controllerProxy: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -81,8 +78,6 @@ contract('Naked Put Option closed before expiry flow', ([accountOwner1]) => { addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controller module @@ -108,13 +103,9 @@ contract('Naked Put Option closed before expiry flow', ([accountOwner1]) => { await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) - // set up controller proxy const controllerProxyAddress = await addressBook.getController() controllerProxy = await Controller.at(controllerProxyAddress) diff --git a/test/integration-tests/open-markets-borrowableMarginPool.test.ts b/test/integration-tests/open-markets-borrowableMarginPool.test.ts deleted file mode 100644 index 1f99a65d9..000000000 --- a/test/integration-tests/open-markets-borrowableMarginPool.test.ts +++ /dev/null @@ -1,404 +0,0 @@ -import { - OtokenFactoryInstance, - OtokenInstance, - MockOtokenInstance, - AddressBookInstance, - MockERC20Instance, - MarginPoolInstance, - BorrowableMarginPoolInstance, - ControllerInstance, - WhitelistInstance, - MockOracleInstance, -} from '../../build/types/truffle-types' - -import { assert } from 'chai' -import { createScaledNumber as createScaled, createTokenAmount, createValidExpiry } from '../utils' -const { expectRevert, time } = require('@openzeppelin/test-helpers') - -const Controller = artifacts.require('Controller.sol') -const MockERC20 = artifacts.require('MockERC20.sol') - -// real contract instances for Testing -const Otoken = artifacts.require('Otoken.sol') -const OTokenFactory = artifacts.require('OtokenFactory.sol') -const AddressBook = artifacts.require('AddressBook.sol') -const Whitelist = artifacts.require('Whitelist.sol') -const Calculator = artifacts.require('MarginCalculator.sol') -const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') -const MarginVault = artifacts.require('MarginVault.sol') -const MockOracle = artifacts.require('MockOracle.sol') - -// used for testing change of Otoken impl address in AddressBook -const MockOtoken = artifacts.require('MockOtoken.sol') - -const ZERO_ADDR = '0x0000000000000000000000000000000000000000' - -enum ActionType { - OpenVault, - MintShortOption, - BurnShortOption, - DepositLongOption, - WithdrawLongOption, - DepositCollateral, - WithdrawCollateral, - SettleVault, - Redeem, - Call, -} - -contract('OTokenFactory + Otoken: Cloning of real otoken instances.', ([owner, user1, user2, random]) => { - let otokenImpl: OtokenInstance - let otoken1: OtokenInstance - let otoken2: OtokenInstance - let addressBook: AddressBookInstance - let otokenFactory: OtokenFactoryInstance - let whitelist: WhitelistInstance - let marginPool: MarginPoolInstance - let borrowableMarginPool: BorrowableMarginPoolInstance - let oracle: MockOracleInstance - - let usdc: MockERC20Instance - let dai: MockERC20Instance - let weth: MockERC20Instance - let randomERC20: MockERC20Instance - - let controller: ControllerInstance - - const strikePrice = createTokenAmount(200) - const isPut = true - let expiry: number - - before('Deploy addressBook, otoken logic, whitelist, Factory contract', async () => { - expiry = createValidExpiry(Number(await time.latest()), 100) - usdc = await MockERC20.new('USDC', 'USDC', 6) - dai = await MockERC20.new('DAI', 'DAI', 18) - weth = await MockERC20.new('wETH', 'WETH', 18) - randomERC20 = await MockERC20.new('RANDOM', 'RAM', 10) - - // Setup AddresBook - addressBook = await AddressBook.new({ from: owner }) - - oracle = await MockOracle.new(addressBook.address, { from: owner }) - otokenImpl = await Otoken.new({ from: owner }) - whitelist = await Whitelist.new(addressBook.address, { from: owner }) - otokenFactory = await OTokenFactory.new(addressBook.address, { from: owner }) - marginPool = await MarginPool.new(addressBook.address) - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) - - const calculator = await Calculator.new(addressBook.address, { from: owner }) - - // setup addressBook - await addressBook.setOtokenImpl(otokenImpl.address, { from: owner }) - await addressBook.setWhitelist(whitelist.address, { from: owner }) - await addressBook.setOtokenFactory(otokenFactory.address, { from: owner }) - await addressBook.setMarginCalculator(calculator.address, { from: owner }) - await addressBook.setMarginPool(marginPool.address, { from: owner }) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: owner, - }) - await addressBook.setOracle(oracle.address, { from: owner }) - - // deploy the controller instance - const lib = await MarginVault.new() - await Controller.link('MarginVault', lib.address) - controller = await Controller.new() - await controller.initialize(addressBook.address, owner) - - // set the controller as controller (so it has access to minting tokens) - await addressBook.setController(controller.address) - controller = await Controller.at(await addressBook.getController()) - - await borrowableMarginPool.setOptionsVaultWhitelistedStatus(user1, true, { from: owner }) - }) - - describe('Otoken Creation before whitelisting', () => { - it('Should revert before admin whitelist any product', async () => { - await expectRevert( - otokenFactory.createOtoken(weth.address, usdc.address, usdc.address, strikePrice, expiry, isPut, { - from: user1, - }), - 'OtokenFactory: Unsupported Product', - ) - }) - }) - - describe('Otoken Creation after whitelisting products and collateral', () => { - before('Whitelist product from admin', async () => { - await whitelist.whitelistCollateral(usdc.address, { from: owner }) - await whitelist.whitelistCollateral(dai.address, { from: owner }) - await whitelist.whitelistProduct(weth.address, usdc.address, usdc.address, isPut, { from: owner }) - await whitelist.whitelistProduct(weth.address, dai.address, dai.address, isPut, { from: owner }) - }) - - it('Should init otoken1 with correct name and symbol', async () => { - // otoken1: eth-usdc option - const targetAddress1 = await otokenFactory.getTargetOtokenAddress( - weth.address, - usdc.address, - usdc.address, - strikePrice, - expiry, - isPut, - ) - await otokenFactory.createOtoken(weth.address, usdc.address, usdc.address, strikePrice, expiry, isPut, { - from: user1, - }) - otoken1 = await Otoken.at(targetAddress1) - assert.isTrue((await otoken1.name()).includes('200Put USDC Collateral')) - assert.isTrue((await otoken1.symbol()).includes('oWETHUSDC/USDC-')) - }) - - it('Should init otoken2 with correct name and symbol', async () => { - // otoken2: eth-dai option - const targetAddress2 = await otokenFactory.getTargetOtokenAddress( - weth.address, - dai.address, - dai.address, - strikePrice, - expiry, - isPut, - ) - await otokenFactory.createOtoken(weth.address, dai.address, dai.address, strikePrice, expiry, isPut, { - from: user2, - }) - otoken2 = await Otoken.at(targetAddress2) - assert.isTrue((await otoken2.name()).includes('200Put DAI Collateral')) - assert.isTrue((await otoken2.symbol()).includes('oWETHDAI')) - }) - - it('The newly created tokens should be whitelisted in the whitelist module', async () => { - assert.equal(await whitelist.isWhitelistedOtoken(otoken1.address), true) - assert.equal(await whitelist.isWhitelistedOtoken(otoken2.address), true) - }) - - it('The owner of whitelist contract can blacklist specific otoken', async () => { - await whitelist.blacklistOtoken(otoken2.address) - - assert.equal(await whitelist.isWhitelistedOtoken(otoken2.address), false) - }) - - it('should revert creating otoken after the owner blacklist the product', async () => { - await whitelist.blacklistProduct(weth.address, usdc.address, usdc.address, isPut) - const newStrikePrice = createScaled(188) - await expectRevert( - otokenFactory.createOtoken(weth.address, usdc.address, usdc.address, newStrikePrice, expiry, isPut, { - from: user1, - }), - 'OtokenFactory: Unsupported Product', - ) - }) - - it('Should revert when calling init after createOtoken', async () => { - /* Should revert because the init function is already called by the factory in createOtoken() */ - await expectRevert( - otoken1.init(addressBook.address, usdc.address, usdc.address, usdc.address, strikePrice, expiry, isPut), - 'Contract instance has already been initialized', - ) - - await expectRevert( - otoken2.init(addressBook.address, randomERC20.address, dai.address, usdc.address, strikePrice, expiry, isPut), - 'Contract instance has already been initialized', - ) - }) - - it('Calling init on otoken logic contract should not affecting the minimal proxies.', async () => { - // someone call init on the logic function for no reason - await otokenImpl.init( - addressBook.address, - randomERC20.address, - randomERC20.address, - weth.address, - strikePrice, - expiry, - isPut, - ) - - const strikeOfOtoken1 = await otoken1.strikeAsset() - const collateralOfOtoken1 = await otoken1.collateralAsset() - - const strikeOfOtoken2 = await otoken2.strikeAsset() - const collateralOfOtoken2 = await otoken2.collateralAsset() - - assert.equal(strikeOfOtoken1, usdc.address) - assert.equal(strikeOfOtoken2, dai.address) - assert.equal(collateralOfOtoken1, usdc.address) - assert.equal(collateralOfOtoken2, dai.address) - }) - }) - - describe('Controller only functions on cloned otokens', () => { - const amountToMint = createTokenAmount(10) - - it('should revert when mintOtoken is called by random address', async () => { - await expectRevert( - otoken1.mintOtoken(user1, amountToMint, { from: random }), - 'Otoken: Only Controller can mint Otokens', - ) - }) - - it('should be able to mint token1 from controller', async () => { - // the controller will call otoken1.mintOtoken() - await whitelist.whitelistCollateral(usdc.address, { from: owner }) - const vaultCounter = 1 - const amountCollateral = createTokenAmount(2000, 6) - await usdc.mint(user1, amountCollateral) - await usdc.approve(borrowableMarginPool.address, amountCollateral, { from: user1 }) - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: user1, - secondAddress: user1, - asset: ZERO_ADDR, - vaultId: vaultCounter, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: user1, - secondAddress: user1, - asset: otoken1.address, - vaultId: vaultCounter, - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: user1, - secondAddress: user1, - asset: usdc.address, - vaultId: vaultCounter, - amount: amountCollateral, - index: '0', - data: ZERO_ADDR, - }, - ] - await controller.operate(actionArgs, { from: user1 }) - // await controller.testMintOtoken(otoken1.address, user1, amountToMint.toString()) - const balance = await otoken1.balanceOf(user1) - assert.equal(balance.toString(), amountToMint.toString()) - }) - - it('should revert when burnOtoken is called by random address', async () => { - await expectRevert( - otoken1.burnOtoken(user1, amountToMint, { from: random }), - 'Otoken: Only Controller can burn Otokens', - ) - }) - - it('should be able to burn tokens from controller', async () => { - const vaultCounter = 1 - const amountCollateral = createTokenAmount(2000, 6) - await otoken1.approve(borrowableMarginPool.address, amountToMint, { from: user1 }) - - const actionArgs = [ - { - actionType: ActionType.BurnShortOption, - owner: user1, - secondAddress: user1, - asset: otoken1.address, - vaultId: vaultCounter, - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.WithdrawCollateral, - owner: user1, - secondAddress: user1, - asset: usdc.address, - vaultId: vaultCounter, - amount: amountCollateral, - index: '0', - data: ZERO_ADDR, - }, - ] - await controller.operate(actionArgs, { from: user1 }) - const balance = await otoken1.balanceOf(user1) - assert.equal(balance.toString(), '0') - }) - }) - - describe('Otoken Implementation address upgrade ', () => { - const amountToMint = createScaled(10) - - before('whitelist product again', async () => { - await whitelist.whitelistProduct(weth.address, usdc.address, usdc.address, isPut, { from: owner }) - }) - - it('should not affect existing otoken instances', async () => { - const newOtoken = await MockOtoken.new() - // mint some otoken1 - const vaultCounter = 1 - const amountCollateral = createTokenAmount(2000, 6) - await usdc.mint(user1, amountCollateral) - await usdc.approve(borrowableMarginPool.address, amountCollateral, { from: user1 }) - const actionArgs = [ - { - actionType: ActionType.MintShortOption, - owner: user1, - secondAddress: user1, - asset: otoken1.address, - vaultId: vaultCounter, - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: user1, - secondAddress: user1, - asset: usdc.address, - vaultId: vaultCounter, - amount: amountCollateral, - index: '0', - data: ZERO_ADDR, - }, - ] - await controller.operate(actionArgs, { from: user1 }) - - // update otokenimpl address in addressbook - await addressBook.setOtokenImpl(newOtoken.address, { from: owner }) - - const balance = await otoken1.balanceOf(user1) - assert.equal(balance.toString(), amountToMint.toString()) - }) - - it('should deploy MockOtoken after upgrade', async () => { - const newExpiry = expiry + 86400 - const address = await otokenFactory.getTargetOtokenAddress( - weth.address, - usdc.address, - usdc.address, - strikePrice, - newExpiry, - isPut, - ) - await otokenFactory.createOtoken(weth.address, usdc.address, usdc.address, strikePrice, newExpiry, isPut) - - const mockedToken: MockOtokenInstance = await MockOtoken.at(address) - // Only MockOtoken has this method, if it return true that means we created a MockOtoken instance. - const inited = await mockedToken.inited() - assert.isTrue(inited) - }) - }) - - describe('Market creation after addressbook update', () => { - before('update the factory address in the address book', async () => { - await addressBook.setOtokenFactory(random) - }) - - it('should revert when trying to create oToken', async () => { - const newStrikePrice = createScaled(400) - await expectRevert( - otokenFactory.createOtoken(weth.address, usdc.address, usdc.address, newStrikePrice, expiry, isPut, { - from: user1, - }), - 'Whitelist: Sender is not OtokenFactory', - ) - }) - }) -}) diff --git a/test/integration-tests/open-markets.test.ts b/test/integration-tests/open-markets.test.ts index 40c2e7ac6..f551244c4 100644 --- a/test/integration-tests/open-markets.test.ts +++ b/test/integration-tests/open-markets.test.ts @@ -5,7 +5,6 @@ import { AddressBookInstance, MockERC20Instance, MarginPoolInstance, - BorrowableMarginPoolInstance, ControllerInstance, WhitelistInstance, MockOracleInstance, @@ -25,7 +24,6 @@ const AddressBook = artifacts.require('AddressBook.sol') const Whitelist = artifacts.require('Whitelist.sol') const Calculator = artifacts.require('MarginCalculator.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const MarginVault = artifacts.require('MarginVault.sol') const MockOracle = artifacts.require('MockOracle.sol') @@ -55,7 +53,6 @@ contract('OTokenFactory + Otoken: Cloning of real otoken instances.', ([owner, u let otokenFactory: OtokenFactoryInstance let whitelist: WhitelistInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let oracle: MockOracleInstance let usdc: MockERC20Instance @@ -84,8 +81,6 @@ contract('OTokenFactory + Otoken: Cloning of real otoken instances.', ([owner, u whitelist = await Whitelist.new(addressBook.address, { from: owner }) otokenFactory = await OTokenFactory.new(addressBook.address, { from: owner }) marginPool = await MarginPool.new(addressBook.address) - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) - const calculator = await Calculator.new(addressBook.address, { from: owner }) // setup addressBook @@ -94,9 +89,6 @@ contract('OTokenFactory + Otoken: Cloning of real otoken instances.', ([owner, u await addressBook.setOtokenFactory(otokenFactory.address, { from: owner }) await addressBook.setMarginCalculator(calculator.address, { from: owner }) await addressBook.setMarginPool(marginPool.address, { from: owner }) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: owner, - }) await addressBook.setOracle(oracle.address, { from: owner }) // deploy the controller instance diff --git a/test/integration-tests/rollover.test.ts b/test/integration-tests/rollover.test.ts index c14767c80..a3facdd6b 100644 --- a/test/integration-tests/rollover.test.ts +++ b/test/integration-tests/rollover.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -49,7 +47,6 @@ contract('Rollover Naked Put Option flow', ([accountOwner1, accountOperator1, bu let controllerImplementation: ControllerInstance let controllerProxy: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -85,8 +82,6 @@ contract('Rollover Naked Put Option flow', ([accountOwner1, accountOperator1, bu addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controller module @@ -112,9 +107,6 @@ contract('Rollover Naked Put Option flow', ([accountOwner1, accountOperator1, bu await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/shortCallSpreadExpireItm.test.ts b/test/integration-tests/shortCallSpreadExpireItm.test.ts index 3a353951b..18d5c444f 100644 --- a/test/integration-tests/shortCallSpreadExpireItm.test.ts +++ b/test/integration-tests/shortCallSpreadExpireItm.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Short Call Spread Option expires Itm flow', ([accountOwner1, nakedBuye let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -85,8 +82,6 @@ contract('Short Call Spread Option expires Itm flow', ([accountOwner1, nakedBuye addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -112,9 +107,6 @@ contract('Short Call Spread Option expires Itm flow', ([accountOwner1, nakedBuye await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/shortCallSpreadExpireOtm.test.ts b/test/integration-tests/shortCallSpreadExpireOtm.test.ts index fe868eb0b..bacbf5c23 100644 --- a/test/integration-tests/shortCallSpreadExpireOtm.test.ts +++ b/test/integration-tests/shortCallSpreadExpireOtm.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Short Call Spread Option expires Otm flow', ([accountOwner1, nakedBuye let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -84,8 +81,6 @@ contract('Short Call Spread Option expires Otm flow', ([accountOwner1, nakedBuye addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -111,9 +106,6 @@ contract('Short Call Spread Option expires Otm flow', ([accountOwner1, nakedBuye await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/shortCallSpreadPreExpiry.test.ts b/test/integration-tests/shortCallSpreadPreExpiry.test.ts index 5c493052f..eb08c7e6e 100644 --- a/test/integration-tests/shortCallSpreadPreExpiry.test.ts +++ b/test/integration-tests/shortCallSpreadPreExpiry.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Short Call Spread Option closed before expiry flow', ([accountOwner1, let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -85,8 +82,6 @@ contract('Short Call Spread Option closed before expiry flow', ([accountOwner1, addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -112,9 +107,6 @@ contract('Short Call Spread Option closed before expiry flow', ([accountOwner1, await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/shortPutSpreadExpireItm.test.ts b/test/integration-tests/shortPutSpreadExpireItm.test.ts index 7f5ed46bd..1c597f650 100644 --- a/test/integration-tests/shortPutSpreadExpireItm.test.ts +++ b/test/integration-tests/shortPutSpreadExpireItm.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Short Put Spread Option expires Itm flow', ([accountOwner1, nakedBuyer let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -85,8 +82,6 @@ contract('Short Put Spread Option expires Itm flow', ([accountOwner1, nakedBuyer addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -112,9 +107,6 @@ contract('Short Put Spread Option expires Itm flow', ([accountOwner1, nakedBuyer await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/shortPutSpreadExpireOtm.test.ts b/test/integration-tests/shortPutSpreadExpireOtm.test.ts index 0fcd642f5..da7414e27 100644 --- a/test/integration-tests/shortPutSpreadExpireOtm.test.ts +++ b/test/integration-tests/shortPutSpreadExpireOtm.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Short Put Spread Option expires Otm flow', ([accountOwner1, nakedBuyer let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -85,8 +82,6 @@ contract('Short Put Spread Option expires Otm flow', ([accountOwner1, nakedBuyer addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -112,9 +107,6 @@ contract('Short Put Spread Option expires Otm flow', ([accountOwner1, nakedBuyer await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/shortPutSpreadPreExpiry.test.ts b/test/integration-tests/shortPutSpreadPreExpiry.test.ts index 2c8d5a405..fb57e6f7c 100644 --- a/test/integration-tests/shortPutSpreadPreExpiry.test.ts +++ b/test/integration-tests/shortPutSpreadPreExpiry.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, } from '../../build/types/truffle-types' import { createTokenAmount, createValidExpiry } from '../utils' @@ -21,7 +20,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -48,7 +46,6 @@ contract('Short Put Spread Option closed before expiry flow', ([accountOwner1, n let controllerProxy: ControllerInstance let controllerImplementation: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -85,8 +82,6 @@ contract('Short Put Spread Option closed before expiry flow', ([accountOwner1, n addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin vault const lib = await MarginVault.new() // setup controllerProxy module @@ -112,9 +107,6 @@ contract('Short Put Spread Option closed before expiry flow', ([accountOwner1, n await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: accountOwner1, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/integration-tests/yieldFarming.test.ts b/test/integration-tests/yieldFarming.test.ts index 741b4c56c..a444e498e 100644 --- a/test/integration-tests/yieldFarming.test.ts +++ b/test/integration-tests/yieldFarming.test.ts @@ -7,7 +7,6 @@ import { ControllerInstance, WhitelistInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, OtokenFactoryInstance, MockPricerInstance, MockCTokenInstance, @@ -24,7 +23,6 @@ const MockERC20 = artifacts.require('MockERC20.sol') const MarginCalculator = artifacts.require('MarginCalculator.sol') const Whitelist = artifacts.require('Whitelist.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const OTokenFactory = artifacts.require('OtokenFactory.sol') @@ -54,7 +52,6 @@ contract('Yield Farming: Naked Put Option closed before expiry flow', ([admin, a let controllerImplementation: ControllerInstance let controllerProxy: ControllerInstance let marginPool: MarginPoolInstance - let borrowableMarginPool: MarginPoolInstance let whitelist: WhitelistInstance let otokenImplementation: OtokenInstance let otokenFactory: OtokenFactoryInstance @@ -87,8 +84,6 @@ contract('Yield Farming: Naked Put Option closed before expiry flow', ([admin, a addressBook = await AddressBook.new() // setup margin pool marginPool = await MarginPool.new(addressBook.address) - // setup margin pool v2 - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // setup margin account const lib = await MarginVault.new() // setup controller module @@ -114,9 +109,6 @@ contract('Yield Farming: Naked Put Option closed before expiry flow', ([admin, a await addressBook.setMarginCalculator(calculator.address) await addressBook.setWhitelist(whitelist.address) await addressBook.setMarginPool(marginPool.address) - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: admin, - }) await addressBook.setOtokenFactory(otokenFactory.address) await addressBook.setOtokenImpl(otokenImplementation.address) await addressBook.setController(controllerImplementation.address) diff --git a/test/unit-tests/borrowableMarginPool.test.ts b/test/unit-tests/borrowableMarginPool.test.ts deleted file mode 100644 index d9ded34a1..000000000 --- a/test/unit-tests/borrowableMarginPool.test.ts +++ /dev/null @@ -1,1087 +0,0 @@ -import { - MockERC20Instance, - MockAddressBookInstance, - MockWhitelistModuleInstance, - WETH9Instance, - MarginPoolInstance, - BorrowableMarginPoolInstance, - MockDumbERC20Instance, - OtokenInstance, -} from '../../build/types/truffle-types' -import { createTokenAmount } from '../utils' - -import BigNumber from 'bignumber.js' - -const { expectRevert, ether } = require('@openzeppelin/test-helpers') - -const MockERC20 = artifacts.require('MockERC20.sol') -const MockDumbERC20 = artifacts.require('MockDumbERC20.sol') -const MockAddressBook = artifacts.require('MockAddressBook.sol') -const MockWhitelist = artifacts.require('MockWhitelistModule.sol') -const WETH9 = artifacts.require('WETH9.sol') -const MarginPool = artifacts.require('BorrowableMarginPool.sol') -const Otoken = artifacts.require('Otoken.sol') - -// address(0) -const ZERO_ADDR = '0x0000000000000000000000000000000000000000' - -contract('MarginPool', ([owner, controllerAddress, farmer, user1, random]) => { - const usdcToMint = ether('100000') - const wethToMint = ether('50') - const otokenAmount = createTokenAmount(10) - - const strikePrice = createTokenAmount(200) - const expiry = 1916380800 // 2030/09/25 0800 UTC - const isPut = false - - const TOTAL_PCT = 10000 - - // ERC20 mocks - let usdc: MockERC20Instance - let weth: WETH9Instance - // DumbER20: Return false when transfer fail. - let dumbToken: MockDumbERC20Instance - // addressbook module mock - let addressBook: MockAddressBookInstance - // whitelist module mock - let whitelist: MockWhitelistModuleInstance - // margin pool - let marginPool: BorrowableMarginPoolInstance - // mock oToken - let otoken: OtokenInstance - - before('Deployment', async () => { - // deploy USDC token - usdc = await MockERC20.new('USDC', 'USDC', 18) - // deploy WETH token for testing - weth = await WETH9.new() - // deploy dumb erc20 - dumbToken = await MockDumbERC20.new('DUSDC', 'DUSDC', 18) - // deploy AddressBook mock - addressBook = await MockAddressBook.new() - // deploy whitelist mock - whitelist = await MockWhitelist.new() - // set Controller module address - await addressBook.setController(controllerAddress) - // set Whitelist module address - await addressBook.setWhitelist(whitelist.address) - - // deploy MarginPool module - marginPool = await MarginPool.new(addressBook.address) - - otoken = await Otoken.new() - - await otoken.init(addressBook.address, weth.address, usdc.address, usdc.address, strikePrice, expiry, isPut, { - from: owner, - }) - - // mint usdc - await usdc.mint(user1, usdcToMint) - // mint usdc - await usdc.mint(controllerAddress, usdcToMint) - // wrap ETH in Controller module level - await weth.deposit({ from: controllerAddress, value: wethToMint }) - - // controller approving infinite amount of WETH to pool - await weth.approve(marginPool.address, wethToMint, { from: controllerAddress }) - // controller approving infinite amount of USDC to pool - await usdc.approve(marginPool.address, usdcToMint, { from: controllerAddress }) - - // transfer to pool - await marginPool.transferToPool(weth.address, controllerAddress, ether('25'), { from: controllerAddress }) - // transfer to pool - await marginPool.transferToPool(usdc.address, controllerAddress, usdcToMint, { from: controllerAddress }) - }) - - describe('MarginPool initialization', () => { - it('should revert if initilized with 0 addressBook address', async () => { - await expectRevert(MarginPool.new(ZERO_ADDR), 'Invalid address book') - }) - }) - - describe('Transfer to pool', () => { - const usdcToTransfer = ether('250') - const wethToTransfer = ether('10') - - it('should revert transfering to pool from caller other than controller address', async () => { - // user approve USDC transfer - await usdc.approve(marginPool.address, usdcToTransfer, { from: user1 }) - - await expectRevert( - marginPool.transferToPool(usdc.address, user1, usdcToTransfer, { from: random }), - 'MarginPool: Sender is not Controller', - ) - }) - - it('should revert transfering to pool an amount equal to zero', async () => { - // user approve USDC transfer - await usdc.approve(marginPool.address, usdcToTransfer, { from: user1 }) - - await expectRevert( - marginPool.transferToPool(usdc.address, user1, ether('0'), { from: controllerAddress }), - 'MarginPool: transferToPool amount is equal to 0', - ) - }) - - it('should revert transfering to pool if the address of the sender is the margin pool', async () => { - // user approve USDC transfer - await usdc.approve(marginPool.address, usdcToTransfer, { from: user1 }) - - await expectRevert( - marginPool.transferToPool(usdc.address, marginPool.address, new BigNumber(usdcToMint).plus(1), { - from: controllerAddress, - }), - 'ERC20: transfer amount exceeds balance', - ) - }) - - it('should transfer to pool from user when called by the controller address', async () => { - const userBalanceBefore = new BigNumber(await usdc.balanceOf(user1)) - const poolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) - - // user approve USDC transfer - await usdc.approve(marginPool.address, usdcToTransfer, { from: user1 }) - - await marginPool.transferToPool(usdc.address, user1, usdcToTransfer, { from: controllerAddress }) - - const userBalanceAfter = new BigNumber(await usdc.balanceOf(user1)) - const poolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) - - assert.equal( - new BigNumber(usdcToTransfer).toString(), - userBalanceBefore.minus(userBalanceAfter).toString(), - 'USDC value transfered from user mismatch', - ) - - assert.equal( - new BigNumber(usdcToTransfer).toString(), - poolBalanceAfter.minus(poolBalanceBefore).toString(), - 'USDC value transfered into pool mismatch', - ) - }) - - it('should transfer WETH to pool from controller when called by the controller address', async () => { - const controllerBalanceBefore = new BigNumber(await weth.balanceOf(controllerAddress)) - const poolBalanceBefore = new BigNumber(await weth.balanceOf(marginPool.address)) - - await marginPool.transferToPool(weth.address, controllerAddress, wethToTransfer, { from: controllerAddress }) - - const controllerBalanceAfter = new BigNumber(await weth.balanceOf(controllerAddress)) - const poolBalanceAfter = new BigNumber(await weth.balanceOf(marginPool.address)) - - assert.equal( - new BigNumber(wethToTransfer).toString(), - controllerBalanceBefore.minus(controllerBalanceAfter).toString(), - 'WETH value transfered from controller mismatch', - ) - - assert.equal( - new BigNumber(wethToTransfer).toString(), - poolBalanceAfter.minus(poolBalanceBefore).toString(), - 'WETH value transfered into pool mismatch', - ) - }) - - it('should revert when transferFrom return false on dumbERC20', async () => { - await expectRevert( - marginPool.transferToPool(dumbToken.address, user1, ether('1'), { from: controllerAddress }), - 'SafeERC20: ERC20 operation did not succeed', - ) - }) - }) - - describe('Transfer to user', () => { - const usdcToTransfer = ether('250') - const wethToTransfer = ether('10') - - it('should revert transfering to user from caller other than controller address', async () => { - await expectRevert( - marginPool.transferToUser(usdc.address, user1, usdcToTransfer, { from: random }), - 'MarginPool: Sender is not Controller', - ) - }) - - it('should revert transfering to user if the user address is the margin pool addres', async () => { - await expectRevert( - marginPool.transferToUser(usdc.address, marginPool.address, usdcToTransfer, { from: controllerAddress }), - 'MarginPool: cannot transfer assets to oneself', - ) - }) - - it('should transfer an ERC-20 to user from pool when called by the controller address', async () => { - const userBalanceBefore = new BigNumber(await usdc.balanceOf(user1)) - const poolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) - - await marginPool.transferToUser(usdc.address, user1, usdcToTransfer, { from: controllerAddress }) - - const userBalanceAfter = new BigNumber(await usdc.balanceOf(user1)) - const poolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) - - assert.equal( - new BigNumber(usdcToTransfer).toString(), - userBalanceAfter.minus(userBalanceBefore).toString(), - 'USDC value transfered to user mismatch', - ) - - assert.equal( - new BigNumber(usdcToTransfer).toString(), - poolBalanceBefore.minus(poolBalanceAfter).toString(), - 'USDC value transfered from pool mismatch', - ) - }) - - it('should transfer WETH to controller from pool, unwrap it and transfer ETH to user when called by the controller address', async () => { - const poolBalanceBefore = new BigNumber(await weth.balanceOf(marginPool.address)) - const userBalanceBefore = new BigNumber(await web3.eth.getBalance(user1)) - - // transfer to controller - await marginPool.transferToUser(weth.address, controllerAddress, wethToTransfer, { from: controllerAddress }) - // unwrap WETH to ETH - await weth.withdraw(wethToTransfer, { from: controllerAddress }) - // send ETH to user - await web3.eth.sendTransaction({ from: controllerAddress, to: user1, value: wethToTransfer }) - - const poolBalanceAfter = new BigNumber(await weth.balanceOf(marginPool.address)) - const userBalanceAfter = new BigNumber(await web3.eth.getBalance(user1)) - - assert.equal( - new BigNumber(wethToTransfer).toString(), - poolBalanceBefore.minus(poolBalanceAfter).toString(), - 'WETH value un-wrapped from pool mismatch', - ) - - assert.equal( - new BigNumber(wethToTransfer).toString(), - userBalanceAfter.minus(userBalanceBefore).toString(), - 'ETH value transfered to user mismatch', - ) - }) - - it('should revert when transfer return false on dumbERC20', async () => { - await dumbToken.mint(user1, ether('1')) - await dumbToken.approve(marginPool.address, ether('1'), { from: user1 }) - await marginPool.transferToPool(dumbToken.address, user1, ether('1'), { from: controllerAddress }) - // let the transfer failed - await dumbToken.setLocked(true) - await expectRevert( - marginPool.transferToUser(dumbToken.address, user1, ether('1'), { from: controllerAddress }), - 'SafeERC20: ERC20 operation did not succeed', - ) - await dumbToken.setLocked(false) - }) - }) - - describe('Transfer multiple assets to pool', () => { - const usdcToTransfer = ether('250') - const wethToTransfer = ether('10') - - it('should revert transfering an array to pool from caller other than controller address', async () => { - // user approve USDC and WETH transfer - await usdc.approve(marginPool.address, usdcToTransfer, { from: user1 }) - await weth.approve(marginPool.address, wethToTransfer, { from: user1 }) - - await expectRevert( - marginPool.batchTransferToPool([usdc.address, weth.address], [user1, user1], [usdcToTransfer, wethToTransfer], { - from: random, - }), - 'MarginPool: Sender is not Controller', - ) - }) - it('should revert transfering to pool an array with an amount equal to zero', async () => { - // user approve USDC transfer - await usdc.approve(marginPool.address, usdcToTransfer, { from: user1 }) - await weth.approve(marginPool.address, wethToTransfer, { from: user1 }) - - await expectRevert( - marginPool.batchTransferToPool([usdc.address, weth.address], [user1, user1], [ether('0'), wethToTransfer], { - from: controllerAddress, - }), - 'MarginPool: transferToPool amount is equal to 0', - ) - }) - - it('should revert with different size arrays', async () => { - await expectRevert( - marginPool.batchTransferToPool( - [usdc.address, weth.address], - [user1, user1], - [usdcToTransfer, usdcToTransfer, usdcToTransfer], - { from: controllerAddress }, - ), - 'MarginPool: batchTransferToPool array lengths are not equal', - ) - }) - - it('should transfer an array including weth and usdc to pool from user/controller when called by the controller address', async () => { - const userUsdcBalanceBefore = new BigNumber(await usdc.balanceOf(user1)) - const poolUsdcBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) - const controllerWethBalanceBefore = new BigNumber(await weth.balanceOf(controllerAddress)) - const poolWethBalanceBefore = new BigNumber(await weth.balanceOf(marginPool.address)) - - // user approve USDC and WETH transfer - await usdc.approve(marginPool.address, usdcToTransfer, { from: user1 }) - await weth.approve(marginPool.address, wethToTransfer, { from: user1 }) - - await marginPool.batchTransferToPool( - [usdc.address, weth.address], - [user1, controllerAddress], - [usdcToTransfer, wethToTransfer], - { from: controllerAddress }, - ) - - const userUsdcBalanceAfter = new BigNumber(await usdc.balanceOf(user1)) - const poolUsdcBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) - const controllerWethBalanceAfter = new BigNumber(await weth.balanceOf(controllerAddress)) - const poolWethBalanceAfter = new BigNumber(await weth.balanceOf(marginPool.address)) - - assert.equal( - new BigNumber(usdcToTransfer).toString(), - userUsdcBalanceBefore.minus(userUsdcBalanceAfter).toString(), - 'USDC value transfered from user mismatch', - ) - - assert.equal( - new BigNumber(usdcToTransfer).toString(), - poolUsdcBalanceAfter.minus(poolUsdcBalanceBefore).toString(), - 'USDC value transfered into pool mismatch', - ) - - assert.equal( - new BigNumber(wethToTransfer).toString(), - controllerWethBalanceBefore.minus(controllerWethBalanceAfter).toString(), - 'WETH value transfered from controller mismatch', - ) - - assert.equal( - new BigNumber(wethToTransfer).toString(), - poolWethBalanceAfter.minus(poolWethBalanceBefore).toString(), - 'WETH value transfered into pool mismatch', - ) - }) - }) - - describe('Transfer multiple assets to user', () => { - const usdcToTransfer = ether('250') - const wethToTransfer = ether('25') - - it('should revert transfering to user from caller other than controller address', async () => { - await expectRevert( - marginPool.batchTransferToUser([usdc.address, weth.address], [user1, user1], [usdcToTransfer, wethToTransfer], { - from: random, - }), - 'MarginPool: Sender is not Controller', - ) - }) - - it('should revert with different size arrays', async () => { - await expectRevert( - marginPool.batchTransferToUser( - [usdc.address, weth.address], - [user1, user1], - [usdcToTransfer, usdcToTransfer, usdcToTransfer], - { from: controllerAddress }, - ), - 'MarginPool: batchTransferToUser array lengths are not equal', - ) - }) - - it('should batch transfer to users when called from controller', async () => { - const userUsdcBalanceBefore = new BigNumber(await usdc.balanceOf(user1)) - const poolUsdcBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) - const controllerWethBalanceBefore = new BigNumber(await weth.balanceOf(controllerAddress)) - const poolWethBalanceBefore = new BigNumber(await weth.balanceOf(marginPool.address)) - - await marginPool.batchTransferToUser( - [usdc.address, weth.address], - [user1, controllerAddress], - [usdcToTransfer, poolWethBalanceBefore], - { from: controllerAddress }, - ) - - const userUsdcBalanceAfter = new BigNumber(await usdc.balanceOf(user1)) - const poolUsdcBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) - const controllerWethBalanceAfter = new BigNumber(await weth.balanceOf(controllerAddress)) - const poolWethBalanceAfter = new BigNumber(await weth.balanceOf(marginPool.address)) - - assert.equal( - usdcToTransfer.toString(), - userUsdcBalanceAfter.minus(userUsdcBalanceBefore).toString(), - 'USDC value transfered to user mismatch', - ) - - assert.equal( - usdcToTransfer.toString(), - poolUsdcBalanceBefore.minus(poolUsdcBalanceAfter).toString(), - 'USDC value transfered from pool mismatch', - ) - - assert.equal( - poolWethBalanceBefore.toString(), - controllerWethBalanceAfter.minus(controllerWethBalanceBefore).toString(), - 'WETH value transfered to controller mismatch', - ) - - assert.equal( - poolWethBalanceBefore.toString(), - poolWethBalanceBefore.minus(poolWethBalanceAfter).toString(), - 'WETH value transfered from pool mismatch', - ) - }) - }) - - describe('Farming', () => { - before(async () => { - // send more usdc to pool - await usdc.mint(marginPool.address, new BigNumber('100')) - }) - - it('should revert setting farmer address from non-owner', async () => { - await expectRevert(marginPool.setFarmer(farmer, { from: random }), 'Ownable: caller is not the owner') - }) - - it('should set farmer address when called from owner', async () => { - await marginPool.setFarmer(farmer, { from: owner }) - - assert.equal(await marginPool.farmer(), farmer, 'farmer address mismatch') - }) - - it('should revert farming when receiver address is equal to zero', async () => { - const poolStoredBalanceBefore = new BigNumber(await marginPool.getStoredBalance(usdc.address)) - const poolBlanaceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) - const amountToFarm = poolBlanaceBefore.minus(poolStoredBalanceBefore) - - await expectRevert( - marginPool.farm(usdc.address, ZERO_ADDR, amountToFarm, { from: farmer }), - 'MarginPool: invalid receiver address', - ) - }) - - it('should revert farming when sender is not farmer address', async () => { - const poolStoredBalanceBefore = new BigNumber(await marginPool.getStoredBalance(usdc.address)) - const poolBlanaceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) - const amountToFarm = poolBlanaceBefore.minus(poolStoredBalanceBefore) - - await expectRevert( - marginPool.farm(usdc.address, random, amountToFarm, { from: random }), - 'MarginPool: Sender is not farmer', - ) - }) - - it('should farm additional USDC', async () => { - const poolStoredBalanceBefore = new BigNumber(await marginPool.getStoredBalance(usdc.address)) - const poolBlanaceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) - const farmerBalanceBefore = new BigNumber(await usdc.balanceOf(farmer)) - const amountToFarm = poolBlanaceBefore.minus(poolStoredBalanceBefore) - - await marginPool.farm(usdc.address, farmer, amountToFarm, { from: farmer }) - - const poolStoredBalanceAfter = new BigNumber(await marginPool.getStoredBalance(usdc.address)) - const poolBlanaceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) - const farmerBalanceAfter = new BigNumber(await usdc.balanceOf(farmer)) - - assert.equal( - poolStoredBalanceBefore.toString(), - poolStoredBalanceAfter.toString(), - 'Pool stored balance mismatch', - ) - assert.equal( - poolBlanaceBefore.minus(poolBlanaceAfter).toString(), - amountToFarm.toString(), - 'Pool balance mismatch', - ) - assert.equal( - farmerBalanceAfter.minus(farmerBalanceBefore).toString(), - amountToFarm.toString(), - 'Farmer balance mismatch', - ) - }) - - it('should revert farming when amount is greater than available balance to farm', async () => { - const amountToFarm = new BigNumber('100000000000') - - await expectRevert( - marginPool.farm(usdc.address, farmer, amountToFarm, { from: farmer }), - 'MarginPool: amount to farm exceeds limit', - ) - }) - - it('should revert farming when transfer return false for dumbERC20', async () => { - const amountExcess = ether('1') - await dumbToken.mint(marginPool.address, amountExcess) - await dumbToken.setLocked(true) - - await expectRevert( - marginPool.farm(dumbToken.address, farmer, amountExcess, { from: farmer }), - 'SafeERC20: ERC20 operation did not succeed', - ) - }) - }) - - describe('Set Borrow Whitelist', () => { - it('should revert calling setBorrowerWhitelistedStatus from non-owner', async () => { - await expectRevert( - marginPool.setBorrowerWhitelistedStatus(random, true, { from: random }), - 'Ownable: caller is not the owner', - ) - }) - - it('should revert calling setBorrowerWhitelistedStatus on zero address', async () => { - await expectRevert( - marginPool.setBorrowerWhitelistedStatus(ZERO_ADDR, true, { from: owner }), - 'MarginPool: Invalid Borrower', - ) - }) - - it('should set whitelist status to true when called from owner', async () => { - await marginPool.setBorrowerWhitelistedStatus(random, true, { from: owner }) - - assert.equal(await marginPool.isWhitelistedBorrower(random), true, 'whitelist status mismatch') - }) - - it('should set whitelist status to false when called from owner', async () => { - await marginPool.setBorrowerWhitelistedStatus(random, true, { from: owner }) - - assert.equal(await marginPool.isWhitelistedBorrower(random), true, 'whitelist status mismatch') - - await marginPool.setBorrowerWhitelistedStatus(random, false, { from: owner }) - - assert.equal(await marginPool.isWhitelistedBorrower(random), false, 'whitelist status mismatch') - }) - }) - - describe('Set oToken Buyer Whitelist', () => { - it('should revert calling setOTokenBuyerWhitelistedStatus from non-owner', async () => { - await expectRevert( - marginPool.setOTokenBuyerWhitelistedStatus(random, true, { from: random }), - 'Ownable: caller is not the owner', - ) - }) - - it('should revert calling setOTokenBuyerWhitelistedStatus on zero address', async () => { - await expectRevert( - marginPool.setOTokenBuyerWhitelistedStatus(ZERO_ADDR, true, { from: owner }), - 'MarginPool: Invalid oToken Buyer', - ) - }) - - it('should set whitelist status to true when called from owner', async () => { - await marginPool.setOTokenBuyerWhitelistedStatus(random, true, { from: owner }) - - assert.equal(await marginPool.isWhitelistedOTokenBuyer(random), true, 'whitelist status mismatch') - }) - - it('should set whitelist status to false when called from owner', async () => { - await marginPool.setOTokenBuyerWhitelistedStatus(random, true, { from: owner }) - - assert.equal(await marginPool.isWhitelistedOTokenBuyer(random), true, 'whitelist status mismatch') - - await marginPool.setOTokenBuyerWhitelistedStatus(random, false, { from: owner }) - - assert.equal(await marginPool.isWhitelistedOTokenBuyer(random), false, 'whitelist status mismatch') - }) - }) - - describe('Set Options Vault Whitelist', () => { - it('should revert calling setOptionsVaultWhitelistedStatus from non-owner', async () => { - await expectRevert( - marginPool.setOptionsVaultWhitelistedStatus(random, true, { from: random }), - 'Ownable: caller is not the owner', - ) - }) - - it('should revert calling setOptionsVaultWhitelistedStatus on zero address', async () => { - await expectRevert( - marginPool.setOptionsVaultWhitelistedStatus(ZERO_ADDR, true, { from: owner }), - 'MarginPool: Invalid Options Vault', - ) - }) - - it('should revert calling setOptionsVaultWhitelistedStatus on retail vault', async () => { - await marginPool.setOptionsVaultToRetailStatus([farmer]) - - await expectRevert( - marginPool.setOptionsVaultWhitelistedStatus(farmer, true, { from: owner }), - 'MarginPool: Cannot whitelist a retail vault', - ) - }) - - it('should set whitelist status to true when called from owner', async () => { - await marginPool.setOptionsVaultWhitelistedStatus(random, true, { from: owner }) - - assert.equal(await marginPool.isWhitelistedOptionsVault(random), true, 'whitelist status mismatch') - }) - - it('should set whitelist status to false when called from owner', async () => { - await marginPool.setOptionsVaultWhitelistedStatus(random, true, { from: owner }) - - assert.equal(await marginPool.isWhitelistedOptionsVault(random), true, 'whitelist status mismatch') - - await marginPool.setOptionsVaultWhitelistedStatus(random, false, { from: owner }) - - assert.equal(await marginPool.isWhitelistedOptionsVault(random), false, 'whitelist status mismatch') - }) - }) - - describe('Set Options Vault to Retail', () => { - it('should revert calling setIsRetailVault from non-owner', async () => { - await expectRevert( - marginPool.setOptionsVaultToRetailStatus([random], { from: random }), - 'Ownable: caller is not the owner', - ) - }) - - it('should set option vault retail vault status to true when called from owner', async () => { - await marginPool.setOptionsVaultToRetailStatus([random], { from: owner }) - - assert.equal(await marginPool.isRetailOptionsVault(random), true, 'whitelist status mismatch') - }) - - it('should set multiple option vaults retail vault status to true when called from owner', async () => { - await marginPool.setOptionsVaultToRetailStatus([random, ZERO_ADDR, owner, controllerAddress], { from: owner }) - - assert.equal(await marginPool.isRetailOptionsVault(random), true, 'whitelist status mismatch') - assert.equal(await marginPool.isRetailOptionsVault(owner), true, 'whitelist status mismatch') - assert.equal(await marginPool.isRetailOptionsVault(controllerAddress), true, 'whitelist status mismatch') - }) - }) - - describe('Set Borrow Percent', () => { - it('should revert calling setBorrowPCT from non-owner', async () => { - await expectRevert( - marginPool.setBorrowPCT(await otoken.collateralAsset(), 1, { from: random }), - 'Ownable: caller is not the owner', - ) - }) - - it('should set borrow percent when called from owner', async () => { - await marginPool.setBorrowPCT(await otoken.collateralAsset(), 100, { from: owner }) - - assert.equal( - new BigNumber(await marginPool.borrowPCT(await otoken.collateralAsset())).toString(), - '100', - 'borrowability status mismatch', - ) - }) - }) - - describe('Borrow', () => { - beforeEach(async () => { - otoken = await Otoken.new() - - await otoken.init(addressBook.address, weth.address, usdc.address, usdc.address, strikePrice, expiry, isPut, { - from: owner, - }) - - await marginPool.setBorrowerWhitelistedStatus(random, true, { from: owner }) - await marginPool.setBorrowerWhitelistedStatus(user1, true, { from: owner }) - await otoken.mintOtoken(user1, otokenAmount, { from: controllerAddress }) - await marginPool.setBorrowPCT(await otoken.collateralAsset(), TOTAL_PCT, { from: owner }) - await whitelist.whitelistOtoken(otoken.address) - }) - - it('should revert borrowing if not whitelisted borrower', async () => { - await marginPool.setBorrowerWhitelistedStatus(random, false, { from: owner }) - - assert.equal( - (await marginPool.borrowable(random, otoken.address)).toString(), - new BigNumber('0').toString(), - 'Borrowable amount mismatch', - ) - - await expectRevert( - marginPool.borrow(otoken.address, 1, { from: random }), - 'MarginPool: Sender is not whitelisted borrower', - ) - }) - - it('should revert borrowing if borrowing 0 of underlying', async () => { - await expectRevert( - marginPool.borrow(otoken.address, 0, { from: random }), - 'MarginPool: Cannot borrow 0 of underlying', - ) - }) - - it('should revert borrowing if borrowPCT = 0', async () => { - await marginPool.setBorrowPCT(await otoken.collateralAsset(), 0, { from: owner }) - - assert.equal( - (await marginPool.borrowable(random, otoken.address)).toString(), - new BigNumber('0').toString(), - 'Borrowable amount mismatch', - ) - - await expectRevert( - marginPool.borrow(otoken.address, 1, { from: random }), - 'MarginPool: Borrowing more than allocated', - ) - }) - - it('should revert borrowing if using expired oToken', async () => { - const otoken2 = await Otoken.new() - - const strikePrice = createTokenAmount(200) - const isPut = false - - await otoken2.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - strikePrice, - 1637792800, - isPut, - { - from: owner, - }, - ) - - // check otoken whitelist - await whitelist.whitelistOtoken(otoken2.address) - - await expectRevert( - marginPool.borrow(otoken2.address, 1, { from: random }), - 'MarginPool: Cannot borrow collateral asset of expired oToken', - ) - }) - - it('should revert borrowing if using put oToken', async () => { - const otoken2 = await Otoken.new() - - const strikePrice = createTokenAmount(200) - const isPut = true - - await otoken2.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - strikePrice, - 1637792800, - isPut, - { - from: owner, - }, - ) - - // check otoken whitelist - await whitelist.whitelistOtoken(otoken2.address) - - await expectRevert( - marginPool.borrow(otoken2.address, 1, { from: random }), - 'MarginPool: oToken is not a call option', - ) - }) - - it('should revert borrowing if using blacklisted oToken', async () => { - const otoken2 = await Otoken.new() - - const strikePrice = createTokenAmount(200) - const isPut = false - - await otoken2.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - strikePrice, - 1637792800, - isPut, - { - from: owner, - }, - ) - - await expectRevert( - marginPool.borrow(otoken2.address, 1, { from: random }), - 'MarginPool: oToken is not whitelisted', - ) - }) - - it('should revert borrowing if borrowing more than allocated', async () => { - await expectRevert( - marginPool.borrow(otoken.address, 1, { from: random }), - 'MarginPool: Borrowing more than allocated', - ) - - await expectRevert( - marginPool.borrow(otoken.address, new BigNumber(await otoken.balanceOf(user1)).plus(1), { from: user1 }), - 'MarginPool: Borrowing more than allocated', - ) - }) - - it('should revert borrowing if borrowing more than allocated (with borrowPCT chance)', async () => { - const borrowPCT = 5000 - - await marginPool.setBorrowPCT(await otoken.collateralAsset(), borrowPCT, { from: owner }) - - const oTokenAmount = new BigNumber(await otoken.balanceOf(user1)) - const oTokenToUnderlying = oTokenAmount.times(new BigNumber(10).exponentiatedBy(10)) - - assert.equal( - oTokenToUnderlying.div(2).toString(), - new BigNumber(await marginPool.borrowable(user1, otoken.address)).toString(), - 'Borrowable amount mismatch', - ) - - await expectRevert( - marginPool.borrow(otoken.address, oTokenAmount.div(2).plus(1), { from: user1 }), - 'MarginPool: Borrowing more than allocated', - ) - }) - - it('should increase borrow capacity after increasing otoken balance', async () => { - const oTokenBalanceBefore = await otoken.balanceOf(user1) - const amtBorrowableBefore = await marginPool.borrowable(user1, otoken.address) - - await otoken.mintOtoken(user1, otokenAmount, { from: controllerAddress }) - - const amtBorrowableAfter = await marginPool.borrowable(user1, otoken.address) - - const oTokenToUnderlying = new BigNumber( - new BigNumber(await otoken.balanceOf(user1)).minus(oTokenBalanceBefore), - ).times(new BigNumber(10).exponentiatedBy(10)) - - assert.equal( - oTokenToUnderlying.toString(), - new BigNumber(amtBorrowableAfter).minus(amtBorrowableBefore).toString(), - 'Borrowable amount mismatch', - ) - }) - - it('should transfer collateral asset to borrower', async () => { - const oTokenBalanceBefore = await otoken.balanceOf(user1) - const borrowerBalanceBefore = new BigNumber(await usdc.balanceOf(user1)) - const amtBorrowableBefore = await marginPool.borrowable(user1, otoken.address) - - const oTokenAmount = new BigNumber(await otoken.balanceOf(user1)) - const oTokenToUnderlying = oTokenAmount.times(new BigNumber(10).exponentiatedBy(10)) - - await otoken.approve(marginPool.address, oTokenAmount, { from: user1 }) - await marginPool.borrow(otoken.address, oTokenAmount, { from: user1 }) - - const borrowerBalanceAfter = new BigNumber(await usdc.balanceOf(user1)) - const amtBorrowableAfter = await marginPool.borrowable(user1, otoken.address) - const oTokenBalanceAfter = await otoken.balanceOf(user1) - - await usdc.approve(marginPool.address, oTokenToUnderlying, { from: user1 }) - await marginPool.repay(otoken.address, oTokenToUnderlying, { from: user1 }) - - assert.equal( - new BigNumber('0').toString(), - new BigNumber(oTokenBalanceAfter).toString(), - 'oToken amount mismatch', - ) - - assert.equal( - oTokenToUnderlying.toString(), - new BigNumber(amtBorrowableBefore).minus(amtBorrowableAfter).toString(), - 'Borrowable amount mismatch', - ) - - assert.equal( - new BigNumber('0').toString(), - new BigNumber(amtBorrowableAfter).toString(), - 'oToken amount mismatch', - ) - - assert.equal( - oTokenToUnderlying.toString(), - new BigNumber(borrowerBalanceAfter).minus(borrowerBalanceBefore).toString(), - 'WETH value transfered from margin pool mismatch', - ) - }) - - it('should transfer collateral asset to borrower after setting borrow PCT', async () => { - const oTokenBalanceBefore = await otoken.balanceOf(user1) - - const oTokenAmount = new BigNumber(await otoken.balanceOf(user1)) - const oTokenToUnderlying = oTokenAmount.times(new BigNumber(10).exponentiatedBy(10)) - - await otoken.approve(marginPool.address, oTokenAmount, { from: user1 }) - - await marginPool.borrow(otoken.address, oTokenAmount.div(4), { from: user1 }) - - // 50% borrowable - await marginPool.setBorrowPCT(await otoken.collateralAsset(), 5000, { from: owner }) - - await marginPool.borrow(otoken.address, oTokenAmount.div(4), { from: user1 }) - - const oTokenBalanceAfter = await otoken.balanceOf(user1) - - assert.equal( - new BigNumber(await marginPool.borrowable(user1, otoken.address)).toString(), - new BigNumber('0').toString(), - 'Borrowable amount mismatch', - ) - - assert.equal( - new BigNumber(oTokenBalanceBefore).div(2).toString(), - new BigNumber(oTokenBalanceBefore).minus(oTokenBalanceAfter).toString(), - 'oToken amount mismatch', - ) - - await usdc.approve(marginPool.address, oTokenToUnderlying, { from: user1 }) - await marginPool.repay(otoken.address, oTokenToUnderlying.div(2), { from: user1 }) - }) - }) - - describe('Repay', () => { - beforeEach(async () => { - otoken = await Otoken.new() - - await otoken.init(addressBook.address, weth.address, usdc.address, usdc.address, strikePrice, expiry, isPut, { - from: owner, - }) - - await marginPool.setBorrowerWhitelistedStatus(random, true, { from: owner }) - await marginPool.setBorrowerWhitelistedStatus(user1, true, { from: owner }) - await otoken.mintOtoken(user1, otokenAmount, { from: controllerAddress }) - await marginPool.setBorrowPCT(await otoken.collateralAsset(), TOTAL_PCT, { from: owner }) - await whitelist.whitelistOtoken(otoken.address) - }) - - it('should revert borrowing if repaying 0 of underlying', async () => { - await expectRevert( - marginPool.repay(otoken.address, 0, { from: user1 }), - 'MarginPool: Cannot repay 0 of underlying', - ) - }) - - it('should revert if repaying more than outstanding borrow', async () => { - const oTokenAmount = new BigNumber(await otoken.balanceOf(user1)) - const oTokenToUnderlying = oTokenAmount.times(new BigNumber(10).exponentiatedBy(10)) - - await otoken.approve(marginPool.address, oTokenAmount, { from: user1 }) - await marginPool.borrow(otoken.address, oTokenAmount, { from: user1 }) - await expectRevert( - marginPool.repay(otoken.address, oTokenToUnderlying.plus(1), { from: user1 }), - 'MarginPool: Repaying more than outstanding borrow amount', - ) - - await usdc.approve(marginPool.address, oTokenToUnderlying, { from: user1 }) - await marginPool.repay(otoken.address, oTokenToUnderlying, { from: user1 }) - }) - - it('should repay the outstanding borrow', async () => { - const oTokenAmount = new BigNumber(await otoken.balanceOf(user1)) - - const oTokenToUnderlying = oTokenAmount.times(new BigNumber(10).exponentiatedBy(10)) - - await otoken.approve(marginPool.address, oTokenAmount, { from: user1 }) - await marginPool.borrow(otoken.address, oTokenAmount, { from: user1 }) - - const oTokenBalanceBefore = await otoken.balanceOf(user1) - const amtBorrowableBefore = await marginPool.borrowable(user1, otoken.address) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) - - await usdc.approve(marginPool.address, oTokenToUnderlying, { from: user1 }) - - await marginPool.repay(otoken.address, oTokenToUnderlying, { from: user1 }) - - const oTokenBalanceAfter = await otoken.balanceOf(user1) - const amtBorrowableAfter = await marginPool.borrowable(user1, otoken.address) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) - - assert.equal( - new BigNumber(oTokenToUnderlying).toString(), - new BigNumber(amtBorrowableAfter).minus(amtBorrowableBefore).toString(), - 'Borrowable amount mismatch', - ) - - assert.equal( - new BigNumber(oTokenToUnderlying).toString(), - new BigNumber(marginPoolBalanceAfter).minus(marginPoolBalanceBefore).toString(), - 'WETH value transfered to margin pool mismatch', - ) - }) - }) - - describe('Repay For', () => { - beforeEach(async () => { - otoken = await Otoken.new() - - await otoken.init(addressBook.address, weth.address, usdc.address, usdc.address, strikePrice, expiry, isPut, { - from: owner, - }) - - await marginPool.setBorrowerWhitelistedStatus(random, true, { from: owner }) - await marginPool.setBorrowerWhitelistedStatus(user1, true, { from: owner }) - await otoken.mintOtoken(user1, otokenAmount, { from: controllerAddress }) - await marginPool.setBorrowPCT(await otoken.collateralAsset(), TOTAL_PCT, { from: owner }) - await whitelist.whitelistOtoken(otoken.address) - }) - - it('should revert if repaying for zero address', async () => { - const oTokenAmount = new BigNumber(await otoken.balanceOf(user1)) - const oTokenToUnderlying = oTokenAmount.times(new BigNumber(10).exponentiatedBy(10)) - - await otoken.approve(marginPool.address, oTokenAmount, { from: user1 }) - await marginPool.borrow(otoken.address, oTokenAmount, { from: user1 }) - await expectRevert( - marginPool.repayFor(otoken.address, oTokenToUnderlying.plus(1), ZERO_ADDR, { from: random }), - 'MarginPool: Borrower cannot be zero address', - ) - - await usdc.approve(marginPool.address, oTokenToUnderlying, { from: user1 }) - await marginPool.repay(otoken.address, oTokenToUnderlying, { from: user1 }) - }) - - it('should revert borrowing if repaying 0 of underlying', async () => { - await expectRevert( - marginPool.repay(otoken.address, 0, { from: user1 }), - 'MarginPool: Cannot repay 0 of underlying', - ) - }) - - it('should revert if repaying more than outstanding borrow', async () => { - const oTokenAmount = new BigNumber(await otoken.balanceOf(user1)) - const oTokenToUnderlying = oTokenAmount.times(new BigNumber(10).exponentiatedBy(10)) - - await otoken.approve(marginPool.address, oTokenAmount, { from: user1 }) - await marginPool.borrow(otoken.address, oTokenAmount, { from: user1 }) - await expectRevert( - marginPool.repayFor(otoken.address, oTokenToUnderlying.plus(1), user1, { from: random }), - 'MarginPool: Repaying more than outstanding borrow amount', - ) - - await usdc.approve(marginPool.address, oTokenToUnderlying, { from: user1 }) - await marginPool.repay(otoken.address, oTokenToUnderlying, { from: user1 }) - }) - - it('should repay the outstanding borrow', async () => { - const oTokenAmount = new BigNumber(await otoken.balanceOf(user1)) - const oTokenToUnderlying = oTokenAmount.times(new BigNumber(10).exponentiatedBy(10)) - - await otoken.approve(marginPool.address, oTokenAmount, { from: user1 }) - await marginPool.borrow(otoken.address, oTokenAmount, { from: user1 }) - - const oTokenBalanceBefore = await otoken.balanceOf(user1) - const amtBorrowableBefore = await marginPool.borrowable(user1, otoken.address) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) - - await usdc.transfer(random, oTokenToUnderlying, { from: user1 }) - - await usdc.approve(marginPool.address, oTokenToUnderlying, { from: random }) - - await marginPool.repayFor(otoken.address, oTokenToUnderlying, user1, { from: random }) - - const oTokenBalanceAfter = await otoken.balanceOf(user1) - const amtBorrowableAfter = await marginPool.borrowable(user1, otoken.address) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) - - assert.equal(oTokenBalanceAfter.toString(), oTokenAmount.toString(), 'oToken amount mismatch') - - assert.equal( - new BigNumber(oTokenToUnderlying).toString(), - new BigNumber(amtBorrowableAfter).minus(amtBorrowableBefore).toString(), - 'Borrowable amount mismatch', - ) - - assert.equal( - new BigNumber(oTokenToUnderlying).toString(), - new BigNumber(marginPoolBalanceAfter).minus(marginPoolBalanceBefore).toString(), - 'WETH value transfered to margin pool mismatch', - ) - }) - }) -}) diff --git a/test/unit-tests/controller.test.ts b/test/unit-tests/controller.test.ts index 7e458c3c7..5a579af9b 100644 --- a/test/unit-tests/controller.test.ts +++ b/test/unit-tests/controller.test.ts @@ -6,7 +6,6 @@ import { MockOracleInstance, MockWhitelistModuleInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, ControllerInstance, AddressBookInstance, OwnedUpgradeabilityProxyInstance, @@ -27,7 +26,6 @@ const MarginCalculator = artifacts.require('MarginCalculator.sol') const MockWhitelistModule = artifacts.require('MockWhitelistModule.sol') const AddressBook = artifacts.require('AddressBook.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') @@ -61,8 +59,6 @@ contract( let calculator: MarginCalculatorInstance // margin pool module let marginPool: MarginPoolInstance - // margin pool module v2 - let borrowableMarginPool: BorrowableMarginPoolInstance // whitelist module mock let whitelist: MockWhitelistModuleInstance // addressbook module mock @@ -87,16 +83,10 @@ contract( calculator = await MarginCalculator.new(oracle.address) // margin pool deployment marginPool = await MarginPool.new(addressBook.address) - // margin pool v2 deployment - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // whitelist module whitelist = await MockWhitelistModule.new() // set margin pool in addressbook await addressBook.setMarginPool(marginPool.address) - // set borrowable margin pool in addressbook - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: owner, - }) // set calculator in addressbook await addressBook.setMarginCalculator(calculator.address) // set oracle in AddressBook @@ -165,6 +155,10 @@ contract( ) }) + it('should revert when set an already operator', async () => { + await expectRevert(controllerProxy.setOperator(accountOperator1, true, { from: accountOwner1 }), 'C9') + }) + it('should be able to remove operator', async () => { await controllerProxy.setOperator(accountOperator1, false, { from: accountOwner1 }) @@ -174,6 +168,10 @@ contract( 'Operator address mismatch', ) }) + + it('should revert when removing an already removed operator', async () => { + await expectRevert(controllerProxy.setOperator(accountOperator1, false, { from: accountOwner1 }), 'C9') + }) }) describe('Vault', () => { @@ -300,10 +298,6 @@ contract( const vaultCounterBefore = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) assert.equal(vaultCounterBefore.toString(), '0', 'vault counter before mismatch') - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const actionArgs = [ { actionType: ActionType.OpenVault, @@ -323,13 +317,7 @@ contract( }) it('should open vault from account operator', async () => { - await borrowableMarginPool.setOptionsVaultWhitelistedStatus(accountOwner1, false, { from: owner }) await controllerProxy.setOperator(accountOperator1, true, { from: accountOwner1 }) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.equal( await controllerProxy.isOperator(accountOwner1, accountOperator1), true, @@ -354,7 +342,6 @@ contract( const vaultCounterAfter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) assert.equal(vaultCounterAfter.minus(vaultCounterBefore).toString(), '1', 'vault counter after mismatch') - assert.equal(finalMarginPool, marginPool.address, 'vault margin pool mismatch') }) }) @@ -383,9 +370,6 @@ contract( describe('deposit long otoken', () => { it('should revert depositing a non-whitelisted long otoken into vault', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const longToDeposit = createTokenAmount(20) const actionArgs = [ { @@ -400,7 +384,7 @@ contract( }, ] - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) + await longOtoken.approve(marginPool.address, longToDeposit, { from: accountOwner1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C17') }) @@ -410,10 +394,6 @@ contract( const vaultCounter = new BigNumber('100') - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const longToDeposit = createTokenAmount(20) const actionArgs = [ { @@ -428,15 +408,13 @@ contract( }, ] - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) + await longOtoken.approve(marginPool.address, longToDeposit, { from: accountOwner1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C35') }) it('should revert depositing long from an address that is not the msg.sender nor the owner account address', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address + const longToDeposit = createTokenAmount(20) const actionArgs = [ { @@ -451,17 +429,13 @@ contract( }, ] - await longOtoken.approve(finalMarginPool, longToDeposit, { from: random }) - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOperator1 }) + await longOtoken.approve(marginPool.address, longToDeposit, { from: random }) + await longOtoken.approve(marginPool.address, longToDeposit, { from: accountOperator1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOperator1 }), 'C16') }) it('should deposit long otoken into vault from account owner', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const longToDeposit = createTokenAmount(20) const actionArgs = [ { @@ -475,13 +449,13 @@ contract( data: ZERO_ADDR, }, ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await longOtoken.balanceOf(accountOwner1)) - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) + await longOtoken.approve(marginPool.address, longToDeposit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await longOtoken.balanceOf(accountOwner1)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -516,10 +490,6 @@ contract( ) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const longToDeposit = createTokenAmount(20) const actionArgs = [ { @@ -533,14 +503,14 @@ contract( data: ZERO_ADDR, }, ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await longOtoken.balanceOf(accountOperator1)) const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOperator1 }) + await longOtoken.approve(marginPool.address, longToDeposit, { from: accountOperator1 }) await controllerProxy.operate(actionArgs, { from: accountOperator1 }) - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await longOtoken.balanceOf(accountOperator1)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -569,10 +539,6 @@ contract( it('should execute depositing long otoken into vault in multiple actions', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const longToDeposit = new BigNumber(createTokenAmount(20)) const actionArgs = [ { @@ -596,16 +562,16 @@ contract( data: ZERO_ADDR, }, ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await longOtoken.balanceOf(accountOwner1)) const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - await longOtoken.approve(finalMarginPool, longToDeposit.multipliedBy(2).toString(), { + await longOtoken.approve(marginPool.address, longToDeposit.multipliedBy(2).toString(), { from: accountOwner1, }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await longOtoken.balanceOf(accountOwner1)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -634,9 +600,6 @@ contract( it('should revert depositing long otoken with amount equal to zero', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const longToDeposit = createTokenAmount(20) const actionArgs = [ { @@ -651,7 +614,7 @@ contract( }, ] - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) + await longOtoken.approve(marginPool.address, longToDeposit, { from: accountOwner1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'V4') }) @@ -674,10 +637,6 @@ contract( await whitelist.whitelistOtoken(expiredLongOtoken.address) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const longToDeposit = createTokenAmount(20) const actionArgs = [ { @@ -692,7 +651,7 @@ contract( }, ] - await expiredLongOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) + await expiredLongOtoken.approve(marginPool.address, longToDeposit, { from: accountOwner1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C18') }) @@ -715,10 +674,6 @@ contract( // whitelist otoken await whitelist.whitelistOtoken(secondLongOtoken.address) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const actionArgs = [ { actionType: ActionType.DepositLongOption, @@ -732,7 +687,7 @@ contract( }, ] - await secondLongOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) + await secondLongOtoken.approve(marginPool.address, longToDeposit, { from: accountOwner1 }) await expectRevert( controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'MarginCalculator: Too many long otokens in the vault', @@ -741,7 +696,6 @@ contract( it('should revert deposting long from controller implementation contract instead of the controller proxy', async () => { await controllerImplementation.initialize(addressBook.address, owner) - const longToDeposit = createTokenAmount(20) const actionArgs = [ { @@ -766,11 +720,7 @@ contract( }, ] - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) - + await longOtoken.approve(marginPool.address, longToDeposit, { from: accountOwner1 }) await expectRevert( controllerImplementation.operate(actionArgs, { from: accountOwner1 }), 'MarginPool: Sender is not Controller', @@ -781,7 +731,6 @@ contract( describe('withdraw long otoken', () => { it('should revert withdrawing long otoken with wrong index from a vault', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const longToWithdraw = createTokenAmount(20) @@ -869,9 +818,6 @@ contract( it('should withdraw long otoken to any random address where msg.sender is account owner', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const longToWithdraw = createTokenAmount(10) @@ -887,13 +833,13 @@ contract( data: ZERO_ADDR, }, ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const receiverBalanceBefore = new BigNumber(await longOtoken.balanceOf(random)) const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const receiverBalanceAfter = new BigNumber(await longOtoken.balanceOf(random)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -923,9 +869,6 @@ contract( ) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const longToWithdraw = createTokenAmount(10) @@ -941,13 +884,13 @@ contract( data: ZERO_ADDR, }, ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const receiverBalanceBefore = new BigNumber(await longOtoken.balanceOf(random)) const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) await controllerProxy.operate(actionArgs, { from: accountOperator1 }) - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const receiverBalanceAfter = new BigNumber(await longOtoken.balanceOf(random)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -971,9 +914,6 @@ contract( it('should execute withdrawing long otoken in mutliple actions', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const longToWithdraw = new BigNumber(createTokenAmount(10)) @@ -999,13 +939,13 @@ contract( data: ZERO_ADDR, }, ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const receiverBalanceBefore = new BigNumber(await longOtoken.balanceOf(accountOwner1)) const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const receiverBalanceAfter = new BigNumber(await longOtoken.balanceOf(accountOwner1)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -1029,9 +969,6 @@ contract( it('should remove otoken address from otoken array if amount is equal to zero after withdrawing', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -1049,12 +986,12 @@ contract( data: ZERO_ADDR, }, ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const receiverBalanceBefore = new BigNumber(await longOtoken.balanceOf(accountOwner1)) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(marginPool.address)) const receiverBalanceAfter = new BigNumber(await longOtoken.balanceOf(accountOwner1)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -1100,12 +1037,6 @@ contract( await whitelist.whitelistOtoken(expiredLongOtoken.address, { from: owner }) // deposit long otoken into vault const vaultId = new BigNumber('1') - - const finalMarginPool = - (await controllerProxy.getVaultWithDetails(accountOwner1, vaultId))[1].toNumber() < 2 - ? marginPool.address - : borrowableMarginPool.address - const actionArgs = [ { actionType: ActionType.DepositLongOption, @@ -1118,7 +1049,7 @@ contract( data: ZERO_ADDR, }, ] - await expiredLongOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) + await expiredLongOtoken.approve(marginPool.address, longToDeposit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultId) assert.equal(vaultAfter.longOtokens.length, 1, 'Vault long otoken array length mismatch') @@ -1172,9 +1103,6 @@ contract( // whitelist usdc await whitelist.whitelistCollateral(usdc.address) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const collateralToDeposit = createTokenAmount(10, usdcDecimals) @@ -1191,13 +1119,13 @@ contract( }, ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -1226,9 +1154,6 @@ contract( it('should deposit a whitelisted collateral asset from account operator', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const collateralToDeposit = createTokenAmount(10, usdcDecimals) @@ -1245,14 +1170,14 @@ contract( }, ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOperator1)) const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOperator1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOperator1 }) await controllerProxy.operate(actionArgs, { from: accountOperator1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOperator1)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -1298,19 +1223,13 @@ contract( }, ] - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C35') }) it('should revert depositing long from an address that is not the msg.sender nor the owner account address', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address + const collateralToDeposit = createTokenAmount(10, usdcDecimals) const actionArgs = [ { @@ -1325,16 +1244,13 @@ contract( }, ] - await usdc.approve(finalMarginPool, collateralToDeposit, { from: random }) - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOperator1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: random }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOperator1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOperator1 }), 'C20') }) it('should revert depositing a collateral asset with amount equal to zero', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const collateralToDeposit = createTokenAmount(0, usdcDecimals) @@ -1351,15 +1267,12 @@ contract( }, ] - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'V7') }) it('should execute depositing collateral into vault in multiple actions', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const collateralToDeposit = new BigNumber(createTokenAmount(20, usdcDecimals)) const actionArgs = [ { @@ -1383,14 +1296,14 @@ contract( data: ZERO_ADDR, }, ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - await usdc.approve(finalMarginPool, collateralToDeposit.multipliedBy(2), { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit.multipliedBy(2), { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -1426,9 +1339,6 @@ contract( await trx.mint(accountOwner1, new BigNumber('1000')) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const collateralDeposit = createTokenAmount(10, wethDecimals) @@ -1445,7 +1355,7 @@ contract( }, ] - await trx.approve(finalMarginPool, collateralDeposit, { from: accountOwner1 }) + await trx.approve(marginPool.address, collateralDeposit, { from: accountOwner1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C21') }) }) @@ -1457,9 +1367,6 @@ contract( await weth.mint(accountOwner1, collateralToDeposit) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const actionArgs = [ { actionType: ActionType.DepositCollateral, @@ -1473,7 +1380,7 @@ contract( }, ] - await weth.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await weth.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await expectRevert( controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'MarginCalculator: Too many collateral assets in the vault', @@ -1551,9 +1458,6 @@ contract( it('should withdraw collateral to any random address where msg.sender is account owner', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const collateralToWithdraw = createTokenAmount(10, usdcDecimals) @@ -1569,13 +1473,13 @@ contract( data: ZERO_ADDR, }, ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const receiverBalanceBefore = new BigNumber(await usdc.balanceOf(random)) const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const receiverBalanceAfter = new BigNumber(await usdc.balanceOf(random)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -1607,10 +1511,6 @@ contract( ) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const collateralToWithdraw = createTokenAmount(10, usdcDecimals) @@ -1626,13 +1526,13 @@ contract( data: ZERO_ADDR, }, ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const receiverBalanceBefore = new BigNumber(await usdc.balanceOf(random)) const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) await controllerProxy.operate(actionArgs, { from: accountOperator1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const receiverBalanceAfter = new BigNumber(await usdc.balanceOf(random)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -1658,9 +1558,6 @@ contract( it('should execute withdrawing collateral asset in mutliple actions', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const collateralToWithdraw = new BigNumber(createTokenAmount(10, usdcDecimals)) @@ -1686,13 +1583,13 @@ contract( data: ZERO_ADDR, }, ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const receiverBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const receiverBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -1718,9 +1615,6 @@ contract( it('should remove collateral asset address from collateral array if amount is equal to zero after withdrawing', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -1738,12 +1632,12 @@ contract( data: ZERO_ADDR, }, ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const receiverBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const receiverBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -1838,9 +1732,6 @@ contract( it('should revert minting using un-marginable collateral asset', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(1e8) @@ -1871,7 +1762,7 @@ contract( // free money await weth.mint(accountOwner1, collateralToDeposit) - await weth.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await weth.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await expectRevert( controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'MarginCalculator: collateral asset not marginable for short asset', @@ -1900,9 +1791,6 @@ contract( it('mint naked short otoken from owner', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(100) @@ -1930,15 +1818,15 @@ contract( }, ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) const senderShortBalanceBefore = new BigNumber(await shortOtoken.balanceOf(accountOwner1)) const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) const senderShortBalanceAfter = new BigNumber(await shortOtoken.balanceOf(accountOwner1)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -1986,9 +1874,6 @@ contract( it('mint naked short otoken from operator', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(100) @@ -2016,15 +1901,15 @@ contract( }, ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOperator1)) const senderShortBalanceBefore = new BigNumber(await shortOtoken.balanceOf(accountOperator1)) const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOperator1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOperator1 }) await controllerProxy.operate(actionArgs, { from: accountOperator1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOperator1)) const senderShortBalanceAfter = new BigNumber(await shortOtoken.balanceOf(accountOperator1)) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) @@ -2103,9 +1988,6 @@ contract( it('should withdraw exceeded collateral from naked short position when net value > 0 ', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') // deposit more collateral @@ -2122,11 +2004,11 @@ contract( data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, excessCollateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, excessCollateralToDeposit, { from: accountOwner1 }) await controllerProxy.operate(firstActionArgs, { from: accountOwner1 }) const vaultBefore = await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const withdrawerBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) const [netValue, isExcess] = await calculator.getExcessCollateral(vaultBefore[0], vaultBefore[1]) @@ -2153,7 +2035,7 @@ contract( await controllerProxy.operate(secondActionArgs, { from: accountOwner1 }) const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const withdrawerBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) assert.equal( @@ -2253,11 +2135,7 @@ contract( }, ] - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOperator1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOperator1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOperator1 }), 'C23') }) }) @@ -2603,7 +2481,6 @@ contract( before(async () => { const vaultCounterBefore = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const expiryTime = new BigNumber(60 * 60) // after 1 hour expiredShortOtoken = await MockOtoken.new() // init otoken @@ -2655,17 +2532,13 @@ contract( }, ] - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) assert.equal( @@ -2710,9 +2583,6 @@ contract( it('should revert minting an expired short otoken', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const collateralToDeposit = new BigNumber(await expiredShortOtoken.strikePrice()).dividedBy(100) @@ -2740,7 +2610,7 @@ contract( }, ] - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOperator1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOperator1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C24') }) @@ -2771,7 +2641,6 @@ contract( describe('Redeem', () => { let shortOtoken: MockOtokenInstance let fakeOtoken: MockOtokenInstance - let finalMarginPool: string before(async () => { const expiryTime = new BigNumber(60 * 60 * 24) // after 1 day @@ -2838,19 +2707,11 @@ contract( data: ZERO_ADDR, }, ] - - finalMarginPool = - !(await borrowableMarginPool.isWhitelistedOTokenBuyer(holder1)) || - new BigNumber(await usdc.balanceOf(borrowableMarginPool.address)).isLessThan(collateralToDeposit) - ? marginPool.address - : borrowableMarginPool.address - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) // transfer minted short otoken to hodler` await shortOtoken.transfer(holder1, amountToMint.toString(), { from: accountOwner1 }) }) - it('should revert exercising non-whitelisted otoken', async () => { const shortAmountToBurn = new BigNumber('1') const actionArgs = [ @@ -2976,13 +2837,13 @@ contract( assert.equal(await controllerProxy.hasExpired(shortOtoken.address), true, 'Short otoken is not expired yet') const payout = createTokenAmount(50, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(holder1)) const senderShortBalanceBefore = new BigNumber(await shortOtoken.balanceOf(holder1)) await controllerProxy.operate(actionArgs, { from: holder1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(holder1)) const senderShortBalanceAfter = new BigNumber(await shortOtoken.balanceOf(holder1)) @@ -3020,7 +2881,7 @@ contract( const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) const amountCollateral = createTokenAmount(1, wethDecimals) await weth.mint(accountOwner1, amountCollateral) - await weth.approve(finalMarginPool, amountCollateral, { from: accountOwner1 }) + await weth.approve(marginPool.address, amountCollateral, { from: accountOwner1 }) const amountOtoken = createTokenAmount(1) const actionArgs = [ { @@ -3104,7 +2965,7 @@ contract( const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) const amountCollateral = createTokenAmount(1, wethDecimals) await weth2.mint(accountOwner1, amountCollateral) - await weth2.approve(finalMarginPool, amountCollateral, { from: accountOwner1 }) + await weth2.approve(marginPool.address, amountCollateral, { from: accountOwner1 }) const amountOtoken = createTokenAmount(1) const actionArgs = [ @@ -3234,7 +3095,7 @@ contract( data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, firstCollateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, firstCollateralToDeposit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) @@ -3270,7 +3131,7 @@ contract( data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, firstCollateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, firstCollateralToDeposit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) // transfer minted short otoken to hodler await firstOtoken.transfer(holder1, amountToMint, { from: accountOwner1 }) @@ -3332,12 +3193,12 @@ contract( ] const payout = createTokenAmount(100, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(holder1)) await controllerProxy.operate(actionArgs, { from: holder1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(holder1)) const senderFirstBalanceAfter = new BigNumber(await firstOtoken.balanceOf(holder1)) const senderSecondBalanceAfter = new BigNumber(await secondOtoken.balanceOf(holder1)) @@ -3380,7 +3241,6 @@ contract( // open new vault, mint naked short, sell it to holder 1 const collateralToDespoit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(100) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const actionArgs = [ { actionType: ActionType.OpenVault, @@ -3403,10 +3263,7 @@ contract( data: ZERO_ADDR, }, ] - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - await usdc.approve(finalMarginPool, collateralToDespoit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDespoit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) }) @@ -3525,10 +3382,6 @@ contract( await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry, createTokenAmount(150), true) await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, createTokenAmount(1), true) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const actionArgs = [ { actionType: ActionType.SettleVault, @@ -3543,7 +3396,7 @@ contract( ] const payout = createTokenAmount(150, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) const proceed = await controllerProxy.getProceed(accountOwner1, vaultCounter) @@ -3551,7 +3404,7 @@ contract( await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) assert.equal( @@ -3585,10 +3438,6 @@ contract( // mint some long otokens, (so we can put it as long) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const longAmount = createTokenAmount(1) const collateralAmount = createTokenAmount(stirkePrice, usdcDecimals) const mintArgs = [ @@ -3623,10 +3472,11 @@ contract( data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, collateralAmount, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralAmount, { from: accountOwner1 }) await controllerProxy.operate(mintArgs, { from: accountOwner1 }) + // Use the newly minted otoken as long and put it in a new vault - const newVaultId = vaultCounter.toNumber() + 1 + const newVulatId = vaultCounter.toNumber() + 1 const newVaultArgs = [ { @@ -3634,7 +3484,7 @@ contract( owner: accountOwner1, secondAddress: accountOwner1, asset: ZERO_ADDR, - vaultId: newVaultId, + vaultId: newVulatId, amount: '0', index: '0', data: ZERO_ADDR, @@ -3644,13 +3494,13 @@ contract( owner: accountOwner1, secondAddress: accountOwner1, asset: longOtoken.address, - vaultId: newVaultId, + vaultId: newVulatId, amount: longAmount, index: '0', data: ZERO_ADDR, }, ] - await longOtoken.approve(finalMarginPool, longAmount, { from: accountOwner1 }) + await longOtoken.approve(marginPool.address, longAmount, { from: accountOwner1 }) await whitelist.whitelistOtoken(longOtoken.address) await controllerProxy.operate(newVaultArgs, { from: accountOwner1 }) // go to expiry @@ -3670,7 +3520,7 @@ contract( owner: accountOwner1, secondAddress: accountOwner1, asset: ZERO_ADDR, - vaultId: newVaultId, + vaultId: newVulatId, amount: '0', index: '0', data: ZERO_ADDR, @@ -3678,14 +3528,15 @@ contract( ] const expectedPayout = new BigNumber(createTokenAmount(stirkePrice - ethPriceAtExpiry, usdcDecimals)) const ownerUSDCBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - const poolOtokenBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const poolOtokenBefore = new BigNumber(await longOtoken.balanceOf(marginPool.address)) - const amountPayout = await controllerProxy.getProceed(accountOwner1, newVaultId) + const amountPayout = await controllerProxy.getProceed(accountOwner1, newVulatId) assert.equal(amountPayout.toString(), expectedPayout.toString(), 'payout calculation mismatch') + await controllerProxy.operate(settleArgs, { from: accountOwner1 }) const ownerUSDCBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - const poolOtokenAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) + const poolOtokenAfter = new BigNumber(await longOtoken.balanceOf(marginPool.address)) assert.equal( ownerUSDCBalanceAfter.toString(), ownerUSDCBalanceBefore.plus(amountPayout).toString(), @@ -3721,10 +3572,6 @@ contract( let collateralToDespoit = createTokenAmount(200, usdcDecimals) let amountToMint = createTokenAmount(1) let vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - let actionArgs = [ { actionType: ActionType.OpenVault, @@ -3757,7 +3604,7 @@ contract( data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, collateralToDespoit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDespoit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) expiryTime = new BigNumber(60 * 60 * 24 * 2) // after 1 day @@ -3777,7 +3624,6 @@ contract( collateralToDespoit = createTokenAmount(200, usdcDecimals) amountToMint = createTokenAmount(1) vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - actionArgs = [ { actionType: ActionType.OpenVault, @@ -3810,7 +3656,7 @@ contract( data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, collateralToDespoit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDespoit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) }) @@ -3823,9 +3669,6 @@ contract( await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry2, createTokenAmount(200), true) await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry2, createTokenAmount(1), true) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const actionArgs = [ { actionType: ActionType.SettleVault, @@ -3850,12 +3693,12 @@ contract( ] const payout = createTokenAmount(400, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) assert.equal( @@ -4031,6 +3874,10 @@ contract( ) }) + it('should revert activating call action restriction when it is already activated', async () => { + await expectRevert(controllerProxy.setCallRestriction(true, { from: owner }), 'C9') + }) + it('should revert calling any arbitrary address when call restriction is activated', async () => { const arbitraryTarget: CallTesterInstance = await CallTester.new() @@ -4079,6 +3926,10 @@ contract( assert.equal(await controllerProxy.callRestricted(), false, 'Call action restriction deactivation failed') }) + + it('should revert deactivating call action restriction when it is already deactivated', async () => { + await expectRevert(controllerProxy.setCallRestriction(false, { from: owner }), 'C9') + }) }) describe('Sync vault latest update timestamp', () => { @@ -4123,10 +3974,6 @@ contract( // open new vault, mint naked short, sell it to holder 1 const collateralToDespoit = new BigNumber(await shortOtokenV1.strikePrice()).dividedBy(100) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const amountToMint = createTokenAmount(1) const actionArgs = [ { @@ -4160,7 +4007,7 @@ contract( data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, collateralToDespoit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDespoit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) //transfer to holder @@ -4175,9 +4022,6 @@ contract( await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry, createTokenAmount(150), true) await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, createTokenAmount(1), true) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const actionArgs = [ { actionType: ActionType.SettleVault, @@ -4192,7 +4036,7 @@ contract( ] const payout = createTokenAmount(150, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) const proceed = await controllerProxy.getProceed(accountOwner1, vaultCounter) @@ -4200,7 +4044,7 @@ contract( await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) assert.equal( @@ -4243,7 +4087,6 @@ contract( before(async () => { const vaultCounterBefore = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const expiryTime = new BigNumber(60 * 60) // after 1 hour shortOtoken = await MockOtoken.new() // init otoken @@ -4294,11 +4137,7 @@ contract( data: ZERO_ADDR, }, ] - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) }) @@ -4314,10 +4153,18 @@ contract( assert.equal(await controllerProxy.partialPauser(), partialPauser, 'pauser address mismatch') }) + it('should revert set pauser address to the same previous address', async () => { + await expectRevert(controllerProxy.setPartialPauser(partialPauser, { from: owner }), 'C9') + }) + it('should revert when pausing the system from address other than pauser', async () => { await expectRevert(controllerProxy.setSystemPartiallyPaused(true, { from: random }), 'C2') }) + it('should revert partially un-pausing an already running system', async () => { + await expectRevert(controllerProxy.setSystemPartiallyPaused(false, { from: partialPauser }), 'C9') + }) + it('should pause system', async () => { const stateBefore = await controllerProxy.systemPartiallyPaused() assert.equal(stateBefore, false, 'System already paused') @@ -4328,6 +4175,10 @@ contract( assert.equal(stateAfter, true, 'System not paused') }) + it('should revert partially pausing an already patially paused system', async () => { + await expectRevert(controllerProxy.setSystemPartiallyPaused(true, { from: partialPauser }), 'C9') + }) + it('should revert opening a vault when system is partially paused', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) const actionArgs = [ @@ -4347,9 +4198,6 @@ contract( it('should revert depositing collateral when system is partially paused', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(1e8) const actionArgs = [ { @@ -4363,15 +4211,12 @@ contract( data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C4') }) it('should revert minting short otoken when system is partially paused', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(1e8) const actionArgs = [ { @@ -4395,7 +4240,7 @@ contract( data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C4') }) @@ -4444,9 +4289,6 @@ contract( await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, createTokenAmount(1), true) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const actionArgs = [ { actionType: ActionType.SettleVault, @@ -4461,12 +4303,12 @@ contract( ] const payout = createTokenAmount(150, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) assert.equal( @@ -4486,10 +4328,6 @@ contract( // transfer to holder await shortOtoken.transfer(holder1, amountToRedeem, { from: accountOwner1 }) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const actionArgs = [ { actionType: ActionType.Redeem, @@ -4505,13 +4343,13 @@ contract( assert.equal(await controllerProxy.hasExpired(shortOtoken.address), true, 'Short otoken is not expired yet') const payout = createTokenAmount(50, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceBefore = new BigNumber(await usdc.balanceOf(holder1)) const senderShortBalanceBefore = new BigNumber(await shortOtoken.balanceOf(holder1)) await controllerProxy.operate(actionArgs, { from: holder1 }) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(marginPool.address)) const senderBalanceAfter = new BigNumber(await usdc.balanceOf(holder1)) const senderShortBalanceAfter = new BigNumber(await shortOtoken.balanceOf(holder1)) @@ -4541,7 +4379,6 @@ contract( await controllerProxy.setSystemPartiallyPaused(false, { from: partialPauser }) const vaultCounterBefore = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const expiryTime = new BigNumber(60 * 60) // after 1 hour shortOtoken = await MockOtoken.new() // init otoken @@ -4592,11 +4429,7 @@ contract( data: ZERO_ADDR, }, ] - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await controllerProxy.operate(actionArgs, { from: accountOwner1 }) }) @@ -4607,6 +4440,10 @@ contract( ) }) + it('should revert set fullPauser address to address zero', async () => { + await expectRevert(controllerProxy.setFullPauser(ZERO_ADDR, { from: owner }), 'C10') + }) + it('should set fullPauser', async () => { await controllerProxy.setFullPauser(fullPauser, { from: owner }) assert.equal(await controllerProxy.fullPauser(), fullPauser, 'Full pauser wrong') @@ -4616,6 +4453,10 @@ contract( await expectRevert(controllerProxy.setSystemFullyPaused(true, { from: random }), 'C1') }) + it('should revert fully un-pausing an already running system', async () => { + await expectRevert(controllerProxy.setSystemFullyPaused(false, { from: fullPauser }), 'C9') + }) + it('should trigger full pause', async () => { const stateBefore = await controllerProxy.systemFullyPaused() assert.equal(stateBefore, false, 'System already in full pause state') @@ -4626,6 +4467,10 @@ contract( assert.equal(stateAfter, true, 'System not in full pause state') }) + it('should revert fully pausing an already fully paused system', async () => { + await expectRevert(controllerProxy.setSystemFullyPaused(true, { from: fullPauser }), 'C9') + }) + it('should revert opening a vault when system is in full pause state', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) const actionArgs = [ @@ -4645,9 +4490,6 @@ contract( it('should revert depositing collateral when system is in full pause state', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(1e8) const actionArgs = [ { @@ -4661,15 +4503,12 @@ contract( data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C5') }) it('should revert minting short otoken when system is in full pause state', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(1e8) const actionArgs = [ { @@ -4693,7 +4532,7 @@ contract( data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C5') }) @@ -4793,7 +4632,7 @@ contract( }) }) - describe('Donate to pool v1', () => { + describe('Donate to pool', () => { it('it should donate to margin pool', async () => { const amountToDonate = createTokenAmount(10, usdcDecimals) const storedBalanceBefore = new BigNumber(await marginPool.getStoredBalance(usdc.address)) @@ -4811,24 +4650,6 @@ contract( }) }) - describe('Donate to borrowable pool', () => { - it('it should donate to margin pool v2', async () => { - const amountToDonate = createTokenAmount(10, usdcDecimals) - const storedBalanceBefore = new BigNumber(await borrowableMarginPool.getStoredBalance(usdc.address)) - - await usdc.approve(borrowableMarginPool.address, amountToDonate, { from: donor }) - await controllerProxy.donateBorrowablePool(usdc.address, amountToDonate, { from: donor }) - - const storedBalanceAfter = new BigNumber(await borrowableMarginPool.getStoredBalance(usdc.address)) - - assert.equal( - storedBalanceAfter.minus(storedBalanceBefore).toString(), - amountToDonate, - 'Donated amount mismatch', - ) - }) - }) - describe('Refresh configuration', () => { it('should revert refreshing configuration from address other than owner', async () => { await expectRevert(controllerProxy.refreshConfiguration({ from: random }), 'Ownable: caller is not the owner') @@ -4848,23 +4669,17 @@ contract( // referesh controller configuration await controllerProxy.refreshConfiguration() - assert.equal(await controllerProxy.oracle(), oracle.address, 'Oracle address mismatch after refresh') - assert.equal( - await controllerProxy.calculator(), - calculator.address, - 'Calculator address mismatch after refresh', - ) - assert.equal(await controllerProxy.pool(), marginPool.address, 'Oracle address mismatch after refresh') - assert.equal(await controllerProxy.whitelist(), whitelist.address, 'Oracle address mismatch after refresh') + const [_whitelist, _oracle, _calculator, _pool] = await controllerProxy.getConfiguration() + assert.equal(_oracle, oracle.address, 'Oracle address mismatch after refresh') + assert.equal(_calculator, calculator.address, 'Calculator address mismatch after refresh') + assert.equal(_pool, marginPool.address, 'Oracle address mismatch after refresh') + assert.equal(_whitelist, whitelist.address, 'Oracle address mismatch after refresh') }) }) describe('Execute an invalid action', () => { it('Should execute transaction with no state updates', async () => { const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') const collateralToDeposit = createTokenAmount(10, usdcDecimals) @@ -4881,7 +4696,7 @@ contract( }, ] - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await expectRevert.unspecified(controllerProxy.operate(actionArgs, { from: accountOwner1 })) }) }) diff --git a/test/unit-tests/controllerBorrowableMarginPool.test.ts b/test/unit-tests/controllerBorrowableMarginPool.test.ts deleted file mode 100644 index 2ec98555a..000000000 --- a/test/unit-tests/controllerBorrowableMarginPool.test.ts +++ /dev/null @@ -1,4889 +0,0 @@ -import { - CallTesterInstance, - MarginCalculatorInstance, - MockOtokenInstance, - MockERC20Instance, - MockOracleInstance, - MockWhitelistModuleInstance, - MarginPoolInstance, - BorrowableMarginPoolInstance, - ControllerInstance, - AddressBookInstance, - OwnedUpgradeabilityProxyInstance, - OtokenImplV1Instance, -} from '../../build/types/truffle-types' -import BigNumber from 'bignumber.js' -import { createTokenAmount, createScaledNumber } from '../utils' - -const { expectRevert, expectEvent, time } = require('@openzeppelin/test-helpers') - -const CallTester = artifacts.require('CallTester.sol') -const MockERC20 = artifacts.require('MockERC20.sol') -const OtokenImplV1 = artifacts.require('OtokenImplV1.sol') -const MockOtoken = artifacts.require('MockOtoken.sol') -const MockOracle = artifacts.require('MockOracle.sol') -const OwnedUpgradeabilityProxy = artifacts.require('OwnedUpgradeabilityProxy.sol') -const MarginCalculator = artifacts.require('MarginCalculator.sol') -const MockWhitelistModule = artifacts.require('MockWhitelistModule.sol') -const AddressBook = artifacts.require('AddressBook.sol') -const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') -const Controller = artifacts.require('Controller.sol') -const MarginVault = artifacts.require('MarginVault.sol') - -// address(0) -const ZERO_ADDR = '0x0000000000000000000000000000000000000000' - -enum ActionType { - OpenVault, - MintShortOption, - BurnShortOption, - DepositLongOption, - WithdrawLongOption, - DepositCollateral, - WithdrawCollateral, - SettleVault, - Redeem, - Call, - InvalidAction, -} - -contract( - 'Controller', - ([owner, accountOwner1, accountOwner2, accountOperator1, holder1, partialPauser, fullPauser, random, donor]) => { - // ERC20 mock - let usdc: MockERC20Instance - let weth: MockERC20Instance - let weth2: MockERC20Instance - // Oracle module - let oracle: MockOracleInstance - // calculator module - let calculator: MarginCalculatorInstance - // margin pool module - let marginPool: MarginPoolInstance - // margin pool module v2 - let borrowableMarginPool: BorrowableMarginPoolInstance - // whitelist module mock - let whitelist: MockWhitelistModuleInstance - // addressbook module mock - let addressBook: AddressBookInstance - // controller module - let controllerImplementation: ControllerInstance - let controllerProxy: ControllerInstance - - const usdcDecimals = 6 - const wethDecimals = 18 - - before('Deployment', async () => { - // addressbook deployment - addressBook = await AddressBook.new() - // ERC20 deployment - usdc = await MockERC20.new('USDC', 'USDC', usdcDecimals) - weth = await MockERC20.new('WETH', 'WETH', wethDecimals) - weth2 = await MockERC20.new('WETH', 'WETH', wethDecimals) - // deploy Oracle module - oracle = await MockOracle.new(addressBook.address, { from: owner }) - // calculator deployment - calculator = await MarginCalculator.new(oracle.address) - // margin pool deployment - marginPool = await MarginPool.new(addressBook.address) - // margin pool v2 deployment - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) - // whitelist module - whitelist = await MockWhitelistModule.new() - // set margin pool in addressbook - await addressBook.setMarginPool(marginPool.address) - // set borrowable margin pool in addressbook - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: owner, - }) - // set calculator in addressbook - await addressBook.setMarginCalculator(calculator.address) - // set oracle in AddressBook - await addressBook.setOracle(oracle.address) - // set whitelist module address - await addressBook.setWhitelist(whitelist.address) - // deploy Controller module - const lib = await MarginVault.new() - await Controller.link('MarginVault', lib.address) - controllerImplementation = await Controller.new() - - // set controller address in AddressBook - await addressBook.setController(controllerImplementation.address, { from: owner }) - - // check controller deployment - const controllerProxyAddress = await addressBook.getController() - controllerProxy = await Controller.at(controllerProxyAddress) - const proxy: OwnedUpgradeabilityProxyInstance = await OwnedUpgradeabilityProxy.at(controllerProxyAddress) - - assert.equal(await proxy.proxyOwner(), addressBook.address, 'Proxy owner address mismatch') - assert.equal(await controllerProxy.owner(), owner, 'Controller owner address mismatch') - assert.equal(await controllerProxy.systemPartiallyPaused(), false, 'system is partially paused') - - // make everyone rich - await usdc.mint(accountOwner1, createTokenAmount(10000, usdcDecimals)) - await usdc.mint(accountOperator1, createTokenAmount(10000, usdcDecimals)) - await usdc.mint(random, createTokenAmount(10000, usdcDecimals)) - await usdc.mint(donor, createTokenAmount(10000, usdcDecimals)) - }) - - describe('Controller initialization', () => { - it('should revert when calling initialize if it is already initalized', async () => { - await expectRevert( - controllerProxy.initialize(addressBook.address, owner), - 'Contract instance has already been initialized', - ) - }) - - it('should revert when calling initialize with addressbook equal to zero', async () => { - const controllerImplementation = await Controller.new() - - await expectRevert(controllerImplementation.initialize(ZERO_ADDR, owner), 'C7') - }) - - it('should revert when calling initialize with owner equal to zero', async () => { - const controllerImplementation = await Controller.new() - - await expectRevert(controllerImplementation.initialize(addressBook.address, ZERO_ADDR), 'C8') - }) - }) - - describe('Account operator', () => { - it('should set operator', async () => { - assert.equal( - await controllerProxy.isOperator(accountOwner1, accountOperator1), - false, - 'Address is already an operator', - ) - - await controllerProxy.setOperator(accountOperator1, true, { from: accountOwner1 }) - - assert.equal( - await controllerProxy.isOperator(accountOwner1, accountOperator1), - true, - 'Operator address mismatch', - ) - }) - - it('should be able to remove operator', async () => { - await controllerProxy.setOperator(accountOperator1, false, { from: accountOwner1 }) - - assert.equal( - await controllerProxy.isOperator(accountOwner1, accountOperator1), - false, - 'Operator address mismatch', - ) - }) - }) - - describe('Vault', () => { - it('should get vault', async () => { - const vaultId = new BigNumber(0) - await controllerProxy.getVault(accountOwner1, vaultId) - }) - - it('should get vault balance', async () => { - const vaultId = new BigNumber(0) - const proceed = await controllerProxy.getProceed(accountOwner1, vaultId) - assert.equal(proceed.toString(), '0') - }) - }) - - describe('Open vault', () => { - it('should revert opening a vault an an account from random address', async () => { - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: random, - asset: ZERO_ADDR, - vaultId: '1', - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - await expectRevert(controllerProxy.operate(actionArgs, { from: random }), 'C6') - }) - - it('should revert opening a vault a vault with id equal to zero', async () => { - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: '0', - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C15') - }) - - it('should revert opening multiple vaults in the same operate call', async () => { - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: '1', - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: '2', - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C13') - }) - - it('should revert opening a vault with vault type other than 0 or 1', async () => { - const invalidVault = web3.eth.abi.encodeParameter('uint256', 2) - - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: '1', - amount: '0', - index: '0', - data: invalidVault, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'A3') - }) - - it('should revert opening multiple vaults for different owners in the same operate call', async () => { - await controllerProxy.setOperator(accountOwner1, true, { from: accountOwner2 }) - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: '1', - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.OpenVault, - owner: accountOwner2, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: '1', - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C12') - }) - - it('should open vault', async () => { - const vaultCounterBefore = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.equal(vaultCounterBefore.toString(), '0', 'vault counter before mismatch') - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounterBefore.toNumber() + 1, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const vaultCounterAfter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.equal(vaultCounterAfter.minus(vaultCounterBefore).toString(), '1', 'vault counter after mismatch') - }) - - it('should open vault from account operator', async () => { - await borrowableMarginPool.setOptionsVaultWhitelistedStatus(accountOwner1, true, { from: owner }) - await controllerProxy.setOperator(accountOperator1, true, { from: accountOwner1 }) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - assert.equal( - await controllerProxy.isOperator(accountOwner1, accountOperator1), - true, - 'Operator address mismatch', - ) - - const vaultCounterBefore = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOperator1, - asset: ZERO_ADDR, - vaultId: vaultCounterBefore.toNumber() + 1, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - await controllerProxy.operate(actionArgs, { from: accountOperator1 }) - - const vaultCounterAfter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.equal(vaultCounterAfter.minus(vaultCounterBefore).toString(), '1', 'vault counter after mismatch') - assert.equal(finalMarginPool, borrowableMarginPool.address, 'vault margin pool mismatch') - }) - }) - - describe('Long otoken', () => { - let longOtoken: MockOtokenInstance - - before(async () => { - const expiryTime = new BigNumber(60 * 60 * 24) // after 1 day - - longOtoken = await MockOtoken.new() - // init otoken - await longOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - - await longOtoken.mintOtoken(accountOwner1, createTokenAmount(100)) - await longOtoken.mintOtoken(accountOperator1, createTokenAmount(100)) - }) - - describe('deposit long otoken', () => { - it('should revert depositing a non-whitelisted long otoken into vault', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const longToDeposit = createTokenAmount(20) - const actionArgs = [ - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C17') - }) - - it('should revert depositing long with invalid vault id', async () => { - // whitelist otoken - await whitelist.whitelistOtoken(longOtoken.address) - - const vaultCounter = new BigNumber('100') - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - const longToDeposit = createTokenAmount(20) - const actionArgs = [ - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C35') - }) - - it('should revert depositing long from an address that is not the msg.sender nor the owner account address', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const longToDeposit = createTokenAmount(20) - const actionArgs = [ - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: random, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - await longOtoken.approve(finalMarginPool, longToDeposit, { from: random }) - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOperator1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOperator1 }), 'C16') - }) - - it('should deposit long otoken into vault from account owner', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const longToDeposit = createTokenAmount(20) - const actionArgs = [ - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await longOtoken.balanceOf(accountOwner1)) - - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await longOtoken.balanceOf(accountOwner1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceAfter.minus(marginPoolBalanceBefore).toString(), - longToDeposit, - 'Margin pool balance long otoken balance mismatch', - ) - assert.equal( - senderBalanceBefore.minus(senderBalanceAfter).toString(), - longToDeposit, - 'Sender balance long otoken balance mismatch', - ) - assert.equal(vaultAfter.longOtokens.length, 1, 'Vault long otoken array length mismatch') - assert.equal( - vaultAfter.longOtokens[0], - longOtoken.address, - 'Long otoken address deposited into vault mismatch', - ) - assert.equal( - new BigNumber(vaultAfter.longAmounts[0]).toString(), - longToDeposit, - 'Long otoken amount deposited into vault mismatch', - ) - }) - - it('should deposit long otoken into vault from account operator', async () => { - assert.equal( - await controllerProxy.isOperator(accountOwner1, accountOperator1), - true, - 'Operator address mismatch', - ) - - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const longToDeposit = createTokenAmount(20) - const actionArgs = [ - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: accountOperator1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await longOtoken.balanceOf(accountOperator1)) - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOperator1 }) - await controllerProxy.operate(actionArgs, { from: accountOperator1 }) - - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await longOtoken.balanceOf(accountOperator1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceAfter.minus(marginPoolBalanceBefore).toString(), - longToDeposit.toString(), - 'Margin pool balance long otoken balance mismatch', - ) - assert.equal( - senderBalanceBefore.minus(senderBalanceAfter).toString(), - longToDeposit.toString(), - 'Sender balance long otoken balance mismatch', - ) - assert.equal(vaultAfter.longOtokens.length, 1, 'Vault long otoken array length mismatch') - assert.equal( - vaultAfter.longOtokens[0], - longOtoken.address, - 'Long otoken address deposited into vault mismatch', - ) - assert.equal( - new BigNumber(vaultAfter.longAmounts[0]).minus(new BigNumber(vaultBefore.longAmounts[0])).toString(), - longToDeposit.toString(), - 'Long otoken amount deposited into vault mismatch', - ) - }) - - it('should execute depositing long otoken into vault in multiple actions', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const longToDeposit = new BigNumber(createTokenAmount(20)) - const actionArgs = [ - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToDeposit.toString(), - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToDeposit.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await longOtoken.balanceOf(accountOwner1)) - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - await longOtoken.approve(finalMarginPool, longToDeposit.multipliedBy(2).toString(), { - from: accountOwner1, - }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await longOtoken.balanceOf(accountOwner1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceAfter.minus(marginPoolBalanceBefore).toString(), - longToDeposit.multipliedBy(2).toString(), - 'Margin pool balance long otoken balance mismatch', - ) - assert.equal( - senderBalanceBefore.minus(senderBalanceAfter).toString(), - longToDeposit.multipliedBy(2).toString(), - 'Sender balance long otoken balance mismatch', - ) - assert.equal(vaultAfter.longOtokens.length, 1, 'Vault long otoken array length mismatch') - assert.equal( - vaultAfter.longOtokens[0], - longOtoken.address, - 'Long otoken address deposited into vault mismatch', - ) - assert.equal( - new BigNumber(vaultAfter.longAmounts[0]).minus(new BigNumber(vaultBefore.longAmounts[0])).toString(), - longToDeposit.multipliedBy(2).toString(), - 'Long otoken amount deposited into vault mismatch', - ) - }) - - it('should revert depositing long otoken with amount equal to zero', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const longToDeposit = createTokenAmount(20) - const actionArgs = [ - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'V4') - }) - - it('should revert depositing an expired long otoken', async () => { - // deploy expired Otoken - const expiredLongOtoken: MockOtokenInstance = await MockOtoken.new() - // init otoken - await expiredLongOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - '1219926985', // 2008 - true, - ) - await expiredLongOtoken.mintOtoken(accountOwner1, new BigNumber('100')) - - // whitelist otoken - await whitelist.whitelistOtoken(expiredLongOtoken.address) - - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const longToDeposit = createTokenAmount(20) - const actionArgs = [ - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: expiredLongOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - await expiredLongOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C18') - }) - - it('should revert when vault have more than 1 long otoken', async () => { - const expiryTime = new BigNumber(60 * 60) // after 1 hour - const longToDeposit = createTokenAmount(20) - // deploy second Otoken - const secondLongOtoken: MockOtokenInstance = await MockOtoken.new() - // init otoken - await secondLongOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - await secondLongOtoken.mintOtoken(accountOwner1, longToDeposit) - // whitelist otoken - await whitelist.whitelistOtoken(secondLongOtoken.address) - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const actionArgs = [ - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: secondLongOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToDeposit, - index: '1', - data: ZERO_ADDR, - }, - ] - - await secondLongOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) - await expectRevert( - controllerProxy.operate(actionArgs, { from: accountOwner1 }), - 'MarginCalculator: Too many long otokens in the vault', - ) - }) - - it('should revert deposting long from controller implementation contract instead of the controller proxy', async () => { - await controllerImplementation.initialize(addressBook.address, owner) - - const longToDeposit = createTokenAmount(20) - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: random, - asset: ZERO_ADDR, - vaultId: '1', - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: 1, - amount: longToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - await longOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) - - await expectRevert( - controllerImplementation.operate(actionArgs, { from: accountOwner1 }), - 'MarginPool: Sender is not Controller', - ) - }) - }) - - describe('withdraw long otoken', () => { - it('should revert withdrawing long otoken with wrong index from a vault', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const longToWithdraw = createTokenAmount(20) - const actionArgs = [ - { - actionType: ActionType.WithdrawLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToWithdraw.toString(), - index: '1', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'V5') - }) - - it('should revert withdrawing long otoken from random address other than account owner or operator', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const longToWithdraw = createTokenAmount(20) - const actionArgs = [ - { - actionType: ActionType.WithdrawLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToWithdraw, - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: random }), 'C6') - }) - - it('should revert withdrawing long otoken amount greater than the vault balance', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - const longToWithdraw = new BigNumber(vaultBefore.longAmounts[0]).plus(1) - const actionArgs = [ - { - actionType: ActionType.WithdrawLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToWithdraw.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert( - controllerProxy.operate(actionArgs, { from: accountOwner1 }), - 'SafeMath: subtraction overflow', - ) - }) - - it('should revert withdrawing long with invalid vault id', async () => { - const vaultCounter = new BigNumber('100') - - const longToWithdraw = createTokenAmount(10) - const actionArgs = [ - { - actionType: ActionType.WithdrawLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToWithdraw, - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C35') - }) - - it('should withdraw long otoken to any random address where msg.sender is account owner', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const longToWithdraw = createTokenAmount(10) - const actionArgs = [ - { - actionType: ActionType.WithdrawLongOption, - owner: accountOwner1, - secondAddress: random, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToWithdraw, - index: '0', - data: ZERO_ADDR, - }, - ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const receiverBalanceBefore = new BigNumber(await longOtoken.balanceOf(random)) - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const receiverBalanceAfter = new BigNumber(await longOtoken.balanceOf(random)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - longToWithdraw.toString(), - 'Margin pool balance long otoken balance mismatch', - ) - assert.equal( - receiverBalanceAfter.minus(receiverBalanceBefore).toString(), - longToWithdraw.toString(), - 'Receiver long otoken balance mismatch', - ) - assert.equal(vaultAfter.longOtokens.length, 1, 'Vault long otoken array length mismatch') - assert.equal( - new BigNumber(vaultBefore.longAmounts[0]).minus(new BigNumber(vaultAfter.longAmounts[0])).toString(), - longToWithdraw.toString(), - 'Long otoken amount in vault after withdraw mismatch', - ) - }) - - it('should withdraw long otoken to any random address where msg.sender is account operator', async () => { - assert.equal( - await controllerProxy.isOperator(accountOwner1, accountOperator1), - true, - 'Operator address mismatch', - ) - - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const longToWithdraw = createTokenAmount(10) - const actionArgs = [ - { - actionType: ActionType.WithdrawLongOption, - owner: accountOwner1, - secondAddress: random, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToWithdraw, - index: '0', - data: ZERO_ADDR, - }, - ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const receiverBalanceBefore = new BigNumber(await longOtoken.balanceOf(random)) - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - await controllerProxy.operate(actionArgs, { from: accountOperator1 }) - - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const receiverBalanceAfter = new BigNumber(await longOtoken.balanceOf(random)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - longToWithdraw.toString(), - 'Margin pool balance long otoken balance mismatch', - ) - assert.equal( - receiverBalanceAfter.minus(receiverBalanceBefore).toString(), - longToWithdraw.toString(), - 'Receiver long otoken balance mismatch', - ) - assert.equal(vaultAfter.longOtokens.length, 1, 'Vault long otoken array length mismatch') - assert.equal( - new BigNumber(vaultBefore.longAmounts[0]).minus(new BigNumber(vaultAfter.longAmounts[0])).toString(), - longToWithdraw.toString(), - 'Long otoken amount in vault after withdraw mismatch', - ) - }) - - it('should execute withdrawing long otoken in mutliple actions', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const longToWithdraw = new BigNumber(createTokenAmount(10)) - const actionArgs = [ - { - actionType: ActionType.WithdrawLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToWithdraw.toString(), - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.WithdrawLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToWithdraw.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const receiverBalanceBefore = new BigNumber(await longOtoken.balanceOf(accountOwner1)) - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const receiverBalanceAfter = new BigNumber(await longOtoken.balanceOf(accountOwner1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - longToWithdraw.multipliedBy(2).toString(), - 'Margin pool balance long otoken balance mismatch', - ) - assert.equal( - receiverBalanceAfter.minus(receiverBalanceBefore).toString(), - longToWithdraw.multipliedBy(2).toString(), - 'Receiver long otoken balance mismatch', - ) - assert.equal(vaultAfter.longOtokens.length, 1, 'Vault long otoken array length mismatch') - assert.equal( - new BigNumber(vaultBefore.longAmounts[0]).minus(new BigNumber(vaultAfter.longAmounts[0])).toString(), - longToWithdraw.multipliedBy(2).toString(), - 'Long otoken amount in vault after withdraw mismatch', - ) - }) - - it('should remove otoken address from otoken array if amount is equal to zero after withdrawing', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - const longToWithdraw = new BigNumber(vaultBefore.longAmounts[0]) - const actionArgs = [ - { - actionType: ActionType.WithdrawLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longToWithdraw.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - const marginPoolBalanceBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const receiverBalanceBefore = new BigNumber(await longOtoken.balanceOf(accountOwner1)) - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - const receiverBalanceAfter = new BigNumber(await longOtoken.balanceOf(accountOwner1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - longToWithdraw.toString(), - 'Margin pool balance long otoken balance mismatch', - ) - assert.equal( - receiverBalanceAfter.minus(receiverBalanceBefore).toString(), - longToWithdraw.toString(), - 'Receiver long otoken balance mismatch', - ) - assert.equal(vaultAfter.longOtokens.length, 1, 'Vault long otoken array length mismatch') - assert.equal(vaultAfter.longOtokens[0], ZERO_ADDR, 'Vault long otoken address after clearing mismatch') - assert.equal( - new BigNumber(vaultBefore.longAmounts[0]).minus(new BigNumber(vaultAfter.longAmounts[0])).toString(), - longToWithdraw.toString(), - 'Long otoken amount in vault after withdraw mismatch', - ) - }) - - describe('withdraw expired long otoken', () => { - let expiredLongOtoken: MockOtokenInstance - - before(async () => { - const expiryTime = new BigNumber(60 * 60) // after 1 hour - expiredLongOtoken = await MockOtoken.new() - // init otoken - await expiredLongOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - // some free money for the account owner - const longToDeposit = createTokenAmount(100) - await expiredLongOtoken.mintOtoken(accountOwner1, longToDeposit) - // whitelist otoken - await whitelist.whitelistOtoken(expiredLongOtoken.address, { from: owner }) - // deposit long otoken into vault - const vaultId = new BigNumber('1') - - const finalMarginPool = - (await controllerProxy.getVaultWithDetails(accountOwner1, vaultId))[1].toNumber() < 2 - ? marginPool.address - : borrowableMarginPool.address - - const actionArgs = [ - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: expiredLongOtoken.address, - vaultId: vaultId.toNumber(), - amount: longToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - await expiredLongOtoken.approve(finalMarginPool, longToDeposit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultId) - assert.equal(vaultAfter.longOtokens.length, 1, 'Vault long otoken array length mismatch') - assert.equal( - vaultAfter.longOtokens[0], - expiredLongOtoken.address, - 'Long otoken address deposited into vault mismatch', - ) - assert.equal( - new BigNumber(vaultAfter.longAmounts[0]).toString(), - longToDeposit.toString(), - 'Long otoken amount deposited into vault mismatch', - ) - }) - - it('should revert withdrawing an expired long otoken', async () => { - // increment time after expiredLongOtoken expiry - await time.increase(3601) // increase time with one hour in seconds - - const vaultId = new BigNumber('1') - const vault = await controllerProxy.getVault(accountOwner1, vaultId) - const longToWithdraw = new BigNumber(vault.longAmounts[0]) - const actionArgs = [ - { - actionType: ActionType.WithdrawLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: expiredLongOtoken.address, - vaultId: vaultId.toNumber(), - amount: longToWithdraw.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - - assert.equal( - await controllerProxy.hasExpired(expiredLongOtoken.address), - true, - 'Long otoken is not expired yet', - ) - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C19') - }) - }) - }) - }) - - describe('Collateral asset', () => { - describe('Deposit collateral asset', () => { - it('should deposit a whitelisted collateral asset from account owner', async () => { - // whitelist usdc - await whitelist.whitelistCollateral(usdc.address) - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToDeposit = createTokenAmount(10, usdcDecimals) - const actionArgs = [ - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceAfter.minus(marginPoolBalanceBefore).toString(), - collateralToDeposit.toString(), - 'Margin pool balance collateral asset balance mismatch', - ) - assert.equal( - senderBalanceBefore.minus(senderBalanceAfter).toString(), - collateralToDeposit.toString(), - 'Sender balance collateral asset balance mismatch', - ) - assert.equal(vaultAfter.collateralAssets.length, 1, 'Vault collateral assets array length mismatch') - assert.equal( - vaultAfter.collateralAssets[0], - usdc.address, - 'Collateral asset address deposited into vault mismatch', - ) - assert.equal( - new BigNumber(vaultAfter.collateralAmounts[0]).toString(), - collateralToDeposit.toString(), - 'Collateral asset amount deposited into vault mismatch', - ) - }) - - it('should deposit a whitelisted collateral asset from account operator', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToDeposit = createTokenAmount(10, usdcDecimals) - const actionArgs = [ - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOperator1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOperator1)) - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOperator1 }) - await controllerProxy.operate(actionArgs, { from: accountOperator1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOperator1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceAfter.minus(marginPoolBalanceBefore).toString(), - collateralToDeposit.toString(), - 'Margin pool balance collateral asset balance mismatch', - ) - assert.equal( - senderBalanceBefore.minus(senderBalanceAfter).toString(), - collateralToDeposit.toString(), - 'Sender balance collateral asset balance mismatch', - ) - assert.equal(vaultAfter.collateralAssets.length, 1, 'Vault collateral assets array length mismatch') - assert.equal( - vaultAfter.collateralAssets[0], - usdc.address, - 'Collateral asset address deposited into vault mismatch', - ) - assert.equal( - new BigNumber(vaultAfter.collateralAmounts[0]) - .minus(new BigNumber(vaultBefore.collateralAmounts[0])) - .toString(), - collateralToDeposit.toString(), - 'Long otoken amount deposited into vault mismatch', - ) - }) - - it('should revert depositing collateral asset with invalid vault id', async () => { - const vaultCounter = new BigNumber('100') - - const collateralToDeposit = createTokenAmount(10, usdcDecimals) - const actionArgs = [ - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C35') - }) - - it('should revert depositing long from an address that is not the msg.sender nor the owner account address', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const collateralToDeposit = createTokenAmount(10, usdcDecimals) - const actionArgs = [ - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: random, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: random }) - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOperator1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOperator1 }), 'C20') - }) - - it('should revert depositing a collateral asset with amount equal to zero', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToDeposit = createTokenAmount(0, usdcDecimals) - const actionArgs = [ - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'V7') - }) - - it('should execute depositing collateral into vault in multiple actions', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const collateralToDeposit = new BigNumber(createTokenAmount(20, usdcDecimals)) - const actionArgs = [ - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit.toString(), - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - await usdc.approve(finalMarginPool, collateralToDeposit.multipliedBy(2), { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceAfter.minus(marginPoolBalanceBefore).toString(), - collateralToDeposit.multipliedBy(2).toString(), - 'Margin pool collateral balance mismatch', - ) - assert.equal( - senderBalanceBefore.minus(senderBalanceAfter).toString(), - collateralToDeposit.multipliedBy(2).toString(), - 'Sender collateral asset balance mismatch', - ) - assert.equal(vaultAfter.collateralAmounts.length, 1, 'Vault collateral asset array length mismatch') - assert.equal( - vaultAfter.collateralAssets[0], - usdc.address, - 'Collateral asset address deposited into vault mismatch', - ) - assert.equal( - new BigNumber(vaultAfter.collateralAmounts[0]) - .minus(new BigNumber(vaultBefore.collateralAmounts[0])) - .toString(), - collateralToDeposit.multipliedBy(2).toString(), - 'Collateral asset amount deposited into vault mismatch', - ) - }) - - describe('Deposit un-whitelisted collateral asset', () => { - it('should revert depositing a collateral asset that is not whitelisted', async () => { - // deploy a shitcoin - const trx: MockERC20Instance = await MockERC20.new('TRX', 'TRX', 18) - await trx.mint(accountOwner1, new BigNumber('1000')) - - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralDeposit = createTokenAmount(10, wethDecimals) - const actionArgs = [ - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: trx.address, - vaultId: vaultCounter.toNumber(), - amount: collateralDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - await trx.approve(finalMarginPool, collateralDeposit, { from: accountOwner1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C21') - }) - }) - - it('should revert when vault have more than 1 collateral type', async () => { - const collateralToDeposit = createTokenAmount(10, wethDecimals) - //whitelist weth to use in this test - await whitelist.whitelistCollateral(weth.address) - await weth.mint(accountOwner1, collateralToDeposit) - - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const actionArgs = [ - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: weth.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit, - index: '1', - data: ZERO_ADDR, - }, - ] - - await weth.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await expectRevert( - controllerProxy.operate(actionArgs, { from: accountOwner1 }), - 'MarginCalculator: Too many collateral assets in the vault', - ) - }) - }) - - describe('withdraw collateral', () => { - it('should revert withdrawing collateral asset with wrong index from a vault', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToWithdraw = createTokenAmount(20, usdcDecimals) - const actionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToWithdraw, - index: '1', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'V8') - }) - - it('should revert withdrawing collateral asset from an invalid id', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToWithdraw = createTokenAmount(20, usdcDecimals) - const actionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: '1350', - amount: collateralToWithdraw, - index: '1', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C35') - }) - - it('should revert withdrawing collateral asset amount greater than the vault balance', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - const collateralToWithdraw = new BigNumber(vaultBefore.collateralAmounts[0]).plus(1) - const actionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToWithdraw.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert( - controllerProxy.operate(actionArgs, { from: accountOwner1 }), - 'SafeMath: subtraction overflow', - ) - }) - - it('should withdraw collateral to any random address where msg.sender is account owner', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToWithdraw = createTokenAmount(10, usdcDecimals) - const actionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: random, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToWithdraw, - index: '0', - data: ZERO_ADDR, - }, - ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const receiverBalanceBefore = new BigNumber(await usdc.balanceOf(random)) - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const receiverBalanceAfter = new BigNumber(await usdc.balanceOf(random)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - collateralToWithdraw.toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - receiverBalanceAfter.minus(receiverBalanceBefore).toString(), - collateralToWithdraw.toString(), - 'Receiver collateral asset balance mismatch', - ) - assert.equal(vaultAfter.collateralAssets.length, 1, 'Vault collateral asset array length mismatch') - assert.equal( - new BigNumber(vaultBefore.collateralAmounts[0]) - .minus(new BigNumber(vaultAfter.collateralAmounts[0])) - .toString(), - collateralToWithdraw.toString(), - 'Collateral asset amount in vault after withdraw mismatch', - ) - }) - - it('should withdraw collateral asset to any random address where msg.sender is account operator', async () => { - assert.equal( - await controllerProxy.isOperator(accountOwner1, accountOperator1), - true, - 'Operator address mismatch', - ) - - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToWithdraw = createTokenAmount(10, usdcDecimals) - const actionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: random, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToWithdraw, - index: '0', - data: ZERO_ADDR, - }, - ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const receiverBalanceBefore = new BigNumber(await usdc.balanceOf(random)) - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - await controllerProxy.operate(actionArgs, { from: accountOperator1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const receiverBalanceAfter = new BigNumber(await usdc.balanceOf(random)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - collateralToWithdraw.toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - receiverBalanceAfter.minus(receiverBalanceBefore).toString(), - collateralToWithdraw.toString(), - 'Receiver collateral asset balance mismatch', - ) - assert.equal(vaultAfter.collateralAssets.length, 1, 'Vault collateral asset array length mismatch') - assert.equal( - new BigNumber(vaultBefore.collateralAmounts[0]) - .minus(new BigNumber(vaultAfter.collateralAmounts[0])) - .toString(), - collateralToWithdraw.toString(), - 'Collateral asset amount in vault after withdraw mismatch', - ) - }) - - it('should execute withdrawing collateral asset in mutliple actions', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToWithdraw = new BigNumber(createTokenAmount(10, usdcDecimals)) - const actionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToWithdraw.toString(), - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToWithdraw.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const receiverBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const receiverBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - collateralToWithdraw.multipliedBy(2).toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - receiverBalanceAfter.minus(receiverBalanceBefore).toString(), - collateralToWithdraw.multipliedBy(2).toString(), - 'Receiver collateral asset balance mismatch', - ) - assert.equal(vaultAfter.collateralAssets.length, 1, 'Vault long otoken array length mismatch') - assert.equal( - new BigNumber(vaultBefore.collateralAmounts[0]) - .minus(new BigNumber(vaultAfter.collateralAmounts[0])) - .toString(), - collateralToWithdraw.multipliedBy(2).toString(), - 'Collateral asset amount in vault after withdraw mismatch', - ) - }) - - it('should remove collateral asset address from collateral array if amount is equal to zero after withdrawing', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - const collateralToWithdraw = new BigNumber(vaultBefore.collateralAmounts[0]) - const actionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToWithdraw.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const receiverBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const receiverBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - collateralToWithdraw.toString(), - 'Margin pool balance long otoken balance mismatch', - ) - assert.equal( - receiverBalanceAfter.minus(receiverBalanceBefore).toString(), - collateralToWithdraw.toString(), - 'Receiver long otoken balance mismatch', - ) - assert.equal(vaultAfter.collateralAssets.length, 1, 'Vault collateral asset array length mismatch') - assert.equal( - vaultAfter.collateralAssets[0], - ZERO_ADDR, - 'Vault collater asset address after clearing mismatch', - ) - assert.equal( - new BigNumber(vaultBefore.collateralAmounts[0]) - .minus(new BigNumber(vaultAfter.collateralAmounts[0])) - .toString(), - collateralToWithdraw.toString(), - 'Collateral asset amount in vault after withdraw mismatch', - ) - }) - }) - }) - - describe('Short otoken', () => { - let longOtoken: MockOtokenInstance - let shortOtoken: MockOtokenInstance - - before(async () => { - const expiryTime = new BigNumber(60 * 60 * 24) // after 1 day - - longOtoken = await MockOtoken.new() - shortOtoken = await MockOtoken.new() - // init otoken - await longOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(250), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - await shortOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - - // whitelist short otoken to be used in the protocol - await whitelist.whitelistOtoken(shortOtoken.address, { from: owner }) - - // give free money - await longOtoken.mintOtoken(accountOwner1, new BigNumber('100')) - await longOtoken.mintOtoken(accountOperator1, new BigNumber('100')) - await usdc.mint(accountOwner1, new BigNumber('1000000')) - await usdc.mint(accountOperator1, new BigNumber('1000000')) - await usdc.mint(random, new BigNumber('1000000')) - }) - - describe('Mint short otoken', () => { - it('should revert minting from random address other than owner or operator', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const amountToMint = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: random, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: random }), 'C6') - }) - - it('should revert minting using un-marginable collateral asset', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(1e8) - const amountToMint = createTokenAmount(1, wethDecimals) - const actionArgs = [ - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: weth.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - - // free money - await weth.mint(accountOwner1, collateralToDeposit) - - await weth.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await expectRevert( - controllerProxy.operate(actionArgs, { from: accountOwner1 }), - 'MarginCalculator: collateral asset not marginable for short asset', - ) - }) - - it('should revert minting short with invalid vault id', async () => { - const vaultCounter = new BigNumber('100') - - const amountToMint = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C35') - }) - - it('mint naked short otoken from owner', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(100) - const amountToMint = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - const senderShortBalanceBefore = new BigNumber(await shortOtoken.balanceOf(accountOwner1)) - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - const senderShortBalanceAfter = new BigNumber(await shortOtoken.balanceOf(accountOwner1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceAfter.minus(marginPoolBalanceBefore).toString(), - collateralToDeposit.toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - senderBalanceBefore.minus(senderBalanceAfter).toString(), - collateralToDeposit.toString(), - 'Sender collateral asset balance mismatch', - ) - assert.equal(vaultAfter.collateralAssets.length, 1, 'Vault collateral asset array length mismatch') - assert.equal(vaultAfter.shortOtokens.length, 1, 'Vault short otoken array length mismatch') - assert.equal( - vaultAfter.collateralAssets[0], - usdc.address, - 'Collateral asset address deposited into vault mismatch', - ) - assert.equal( - vaultAfter.shortOtokens[0], - shortOtoken.address, - 'Short otoken address deposited into vault mismatch', - ) - assert.equal( - senderShortBalanceAfter.minus(senderShortBalanceBefore).toString(), - amountToMint.toString(), - 'Short otoken amount minted mismatch', - ) - assert.equal( - new BigNumber(vaultAfter.collateralAmounts[0]) - .minus(new BigNumber(vaultBefore.collateralAmounts[0])) - .toString(), - collateralToDeposit.toString(), - 'Collateral asset amount deposited into vault mismatch', - ) - assert.equal( - new BigNumber(vaultAfter.shortAmounts[0]).toString(), - amountToMint.toString(), - 'Short otoken amount minted into vault mismatch', - ) - }) - - it('mint naked short otoken from operator', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(100) - const amountToMint = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOperator1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOperator1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOperator1)) - const senderShortBalanceBefore = new BigNumber(await shortOtoken.balanceOf(accountOperator1)) - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOperator1 }) - await controllerProxy.operate(actionArgs, { from: accountOperator1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOperator1)) - const senderShortBalanceAfter = new BigNumber(await shortOtoken.balanceOf(accountOperator1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - marginPoolBalanceAfter.minus(marginPoolBalanceBefore).toString(), - collateralToDeposit.toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - senderBalanceBefore.minus(senderBalanceAfter).toString(), - collateralToDeposit.toString(), - 'Sender collateral asset balance mismatch', - ) - assert.equal(vaultAfter.collateralAssets.length, 1, 'Vault collateral asset array length mismatch') - assert.equal(vaultAfter.shortOtokens.length, 1, 'Vault short otoken array length mismatch') - assert.equal( - vaultAfter.collateralAssets[0], - usdc.address, - 'Collateral asset address deposited into vault mismatch', - ) - assert.equal( - vaultAfter.shortOtokens[0], - shortOtoken.address, - 'Short otoken address deposited into vault mismatch', - ) - assert.equal( - senderShortBalanceAfter.minus(senderShortBalanceBefore).toString(), - amountToMint.toString(), - 'Short otoken amount minted mismatch', - ) - assert.equal( - new BigNumber(vaultAfter.collateralAmounts[0]) - .minus(new BigNumber(vaultBefore.collateralAmounts[0])) - .toString(), - collateralToDeposit.toString(), - 'Collateral asset amount deposited into vault mismatch', - ) - assert.equal( - new BigNumber(vaultAfter.shortAmounts[0]).minus(new BigNumber(vaultBefore.shortAmounts[0])).toString(), - amountToMint.toString(), - 'Short otoken amount minted into vault mismatch', - ) - }) - - it('should revert withdrawing collateral from naked short position when net value is equal to zero', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const vaultBefore = await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter) - - const [netValue, isExcess] = await calculator.getExcessCollateral(vaultBefore[0], vaultBefore[1]) - - const proceed = await controllerProxy.getProceed(accountOwner1, vaultCounter) - assert.equal(netValue.toString(), proceed.toString()) - - assert.equal(netValue.toString(), '0', 'Position net value mistmatch') - assert.equal(isExcess, true, 'Position collateral excess mismatch') - - const collateralToWithdraw = new BigNumber(vaultBefore[0].collateralAmounts[0]) - const actionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToWithdraw.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C14') - }) - - it('should withdraw exceeded collateral from naked short position when net value > 0 ', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - // deposit more collateral - const excessCollateralToDeposit = createTokenAmount(50, usdcDecimals) - const firstActionArgs = [ - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: excessCollateralToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - await usdc.approve(finalMarginPool, excessCollateralToDeposit, { from: accountOwner1 }) - await controllerProxy.operate(firstActionArgs, { from: accountOwner1 }) - - const vaultBefore = await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const withdrawerBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - - const [netValue, isExcess] = await calculator.getExcessCollateral(vaultBefore[0], vaultBefore[1]) - - const proceed = await controllerProxy.getProceed(accountOwner1, vaultCounter) - assert.equal(netValue.toString(), proceed.toString()) - - assert.equal(netValue.toString(), excessCollateralToDeposit.toString(), 'Position net value mistmatch') - assert.equal(isExcess, true, 'Position collateral excess mismatch') - - const secondActionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: excessCollateralToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - await controllerProxy.operate(secondActionArgs, { from: accountOwner1 }) - - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const withdrawerBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - excessCollateralToDeposit.toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - withdrawerBalanceAfter.minus(withdrawerBalanceBefore).toString(), - excessCollateralToDeposit.toString(), - 'Receiver collateral asset balance mismatch', - ) - assert.equal(vaultAfter.collateralAssets.length, 1, 'Vault collateral asset array length mismatch') - assert.equal( - new BigNumber(vaultBefore[0].collateralAmounts[0]) - .minus(new BigNumber(vaultAfter.collateralAmounts[0])) - .toString(), - excessCollateralToDeposit.toString(), - 'Collateral asset amount in vault after withdraw mismatch', - ) - }) - - it('should revert when vault have more than 1 short otoken', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - await whitelist.whitelistOtoken(longOtoken.address, { from: owner }) - - const amountToMint = '1' - - const actionArgs = [ - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '1', - data: ZERO_ADDR, - }, - ] - - await expectRevert( - controllerProxy.operate(actionArgs, { from: accountOwner1 }), - 'MarginCalculator: Too many short otokens in the vault', - ) - }) - - describe('Mint un-whitelisted short otoken', () => { - it('should revert minting an otoken that is not whitelisted in Whitelist module', async () => { - const expiryTime = new BigNumber(60 * 60 * 24) // after 1 day - - const notWhitelistedShortOtoken: MockOtokenInstance = await MockOtoken.new() - await notWhitelistedShortOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - - const collateralToDeposit = new BigNumber(await notWhitelistedShortOtoken.strikePrice()).dividedBy(100) - const amountToMint = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOperator1, - secondAddress: accountOperator1, - asset: ZERO_ADDR, - vaultId: '1', - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOperator1, - secondAddress: accountOperator1, - asset: notWhitelistedShortOtoken.address, - vaultId: '1', - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOperator1, - secondAddress: accountOperator1, - asset: usdc.address, - vaultId: '1', - amount: collateralToDeposit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOperator1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOperator1 }), 'C23') - }) - }) - - describe('Mint negligible amount', () => { - let oneDollarPut: MockOtokenInstance - let smallestPut: MockOtokenInstance - before('create options with small strike price', async () => { - oneDollarPut = await MockOtoken.new() - smallestPut = await MockOtoken.new() - // init otoken - await oneDollarPut.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(1), - new BigNumber(await time.latest()).plus(86400), - true, - ) - await smallestPut.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - 1, - new BigNumber(await time.latest()).plus(86400), - true, - ) - await whitelist.whitelistOtoken(oneDollarPut.address) - await whitelist.whitelistOtoken(smallestPut.address) - }) - it('should revert if trying to mint 1 wei of oToken with strikePrice = 1 USD without putting collateral', async () => { - const vaultId = (await controllerProxy.getAccountVaultCounter(accountOwner2)).toNumber() + 1 - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner2, - secondAddress: accountOwner2, - asset: ZERO_ADDR, - vaultId: vaultId, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner2, - secondAddress: accountOwner2, - asset: oneDollarPut.address, - vaultId: vaultId, - amount: '1', - index: '0', - data: ZERO_ADDR, - }, - ] - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner2 }), 'C14') - }) - - it('should revert minting 1 wei of oToken with minimal strikePrice without putting collateral', async () => { - const vaultId = (await controllerProxy.getAccountVaultCounter(accountOwner2)).toNumber() + 1 - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner2, - secondAddress: accountOwner2, - asset: ZERO_ADDR, - vaultId: vaultId, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner2, - secondAddress: accountOwner2, - asset: smallestPut.address, - vaultId: vaultId, - amount: '1', - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner2 }), 'C14') - }) - }) - }) - - describe('Burn short otoken', () => { - it('should revert burning short otoken with wrong index from a vault', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const shortOtokenToBurn = await shortOtoken.balanceOf(accountOwner1) - const actionArgs = [ - { - actionType: ActionType.BurnShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: shortOtokenToBurn.toString(), - index: '1', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'V2') - }) - - it('should revert burning when there is no enough balance', async () => { - // transfer operator balance - const operatorShortBalance = new BigNumber(await shortOtoken.balanceOf(accountOperator1)) - await shortOtoken.transfer(accountOwner1, operatorShortBalance, { from: accountOperator1 }) - - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const shortOtokenToBurn = new BigNumber(await shortOtoken.balanceOf(accountOwner1)) - const actionArgs = [ - { - actionType: ActionType.BurnShortOption, - owner: accountOwner1, - secondAddress: accountOperator1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: shortOtokenToBurn.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert( - controllerProxy.operate(actionArgs, { from: accountOperator1 }), - 'ERC20: burn amount exceeds balance', - ) - - // transfer back - await shortOtoken.transfer(accountOperator1, operatorShortBalance, { from: accountOwner1 }) - }) - - it('should revert burning when called from an address other than account owner or operator', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const shortOtokenToBurn = new BigNumber(await shortOtoken.balanceOf(accountOwner1)) - const actionArgs = [ - { - actionType: ActionType.BurnShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: shortOtokenToBurn.toString(), - index: '1', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: random }), 'C6') - }) - - it('should revert minting short with invalid vault id', async () => { - const vaultCounter = new BigNumber('100') - - const shortOtokenToBurn = new BigNumber(await shortOtoken.balanceOf(accountOperator1)) - const actionArgs = [ - { - actionType: ActionType.BurnShortOption, - owner: accountOwner1, - secondAddress: accountOperator1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: shortOtokenToBurn.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C35') - }) - - it('should revert depositing long from an address that is not the msg.sender nor the owner account address', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const shortOtokenToBurn = new BigNumber(await shortOtoken.balanceOf(accountOperator1)) - const actionArgs = [ - { - actionType: ActionType.BurnShortOption, - owner: accountOwner1, - secondAddress: random, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: shortOtokenToBurn.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOperator1 }), 'C25') - }) - - it('should burn short otoken when called from account operator', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - const shortOtokenToBurn = new BigNumber(await shortOtoken.balanceOf(accountOperator1)) - const actionArgs = [ - { - actionType: ActionType.BurnShortOption, - owner: accountOwner1, - secondAddress: accountOperator1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: shortOtokenToBurn.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - const sellerBalanceBefore = new BigNumber(await shortOtoken.balanceOf(accountOperator1)) - - await controllerProxy.operate(actionArgs, { from: accountOperator1 }) - - const sellerBalanceAfter = new BigNumber(await shortOtoken.balanceOf(accountOperator1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - sellerBalanceBefore.minus(sellerBalanceAfter).toString(), - shortOtokenToBurn.toString(), - 'Short otoken burned amount mismatch', - ) - assert.equal(vaultAfter.shortOtokens.length, 1, 'Vault short otoken array length mismatch') - assert.equal( - vaultAfter.shortOtokens[0], - shortOtoken.address, - 'Vault short otoken address after burning mismatch', - ) - assert.equal( - new BigNumber(vaultBefore.shortAmounts[0]).minus(new BigNumber(vaultAfter.shortAmounts[0])).toString(), - shortOtokenToBurn.toString(), - 'Short otoken amount in vault after burn mismatch', - ) - }) - - it('should remove short otoken address from short otokens array if amount is equal to zero after burning', async () => { - // send back all short otoken to owner - const operatorShortBalance = new BigNumber(await shortOtoken.balanceOf(accountOperator1)) - await shortOtoken.transfer(accountOwner1, operatorShortBalance, { from: accountOperator1 }) - - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const vaultBefore = await controllerProxy.getVault(accountOwner1, vaultCounter) - - const shortOtokenToBurn = new BigNumber(vaultBefore.shortAmounts[0]) - const actionArgs = [ - { - actionType: ActionType.BurnShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: shortOtokenToBurn.toString(), - index: '0', - data: ZERO_ADDR, - }, - ] - const sellerBalanceBefore = new BigNumber(await shortOtoken.balanceOf(accountOwner1)) - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const sellerBalanceAfter = new BigNumber(await shortOtoken.balanceOf(accountOwner1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - - assert.equal( - sellerBalanceBefore.minus(sellerBalanceAfter).toString(), - shortOtokenToBurn.toString(), - 'Short otoken burned amount mismatch', - ) - assert.equal(vaultAfter.shortOtokens.length, 1, 'Vault short otoken array length mismatch') - assert.equal(vaultAfter.shortOtokens[0], ZERO_ADDR, 'Vault short otoken address after clearing mismatch') - assert.equal( - new BigNumber(vaultBefore.shortAmounts[0]).minus(new BigNumber(vaultAfter.shortAmounts[0])).toString(), - shortOtokenToBurn.toString(), - 'Short otoken amount in vault after burn mismatch', - ) - }) - - it('should mint and burn at the same transaction', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - // const vaultCounter = 1 - const amountToMint = createScaledNumber(1) - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.BurnShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - ] - const senderShortBalanceBefore = new BigNumber(await shortOtoken.balanceOf(accountOwner1)) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - const senderShortBalanceAfter = new BigNumber(await shortOtoken.balanceOf(accountOwner1)) - const vaultAfter = await controllerProxy.getVault(accountOwner1, vaultCounter) - assert.equal(vaultAfter.shortOtokens.length, 1, 'Vault short otoken array length mismatch') - assert.equal(vaultAfter.shortOtokens[0], ZERO_ADDR) - assert.equal( - senderShortBalanceBefore.toString(), - senderShortBalanceAfter.toString(), - 'Sender short otoken amount mismatch', - ) - }) - - describe('Expired otoken', () => { - let expiredShortOtoken: MockOtokenInstance - - before(async () => { - const vaultCounterBefore = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const expiryTime = new BigNumber(60 * 60) // after 1 hour - expiredShortOtoken = await MockOtoken.new() - // init otoken - await expiredShortOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - - // whitelist otoken to be minted - await whitelist.whitelistOtoken(expiredShortOtoken.address, { from: owner }) - - const collateralToDeposit = new BigNumber(await expiredShortOtoken.strikePrice()).dividedBy(100) - const amountToMint = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounterBefore.toNumber() + 1, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: expiredShortOtoken.address, - vaultId: vaultCounterBefore.toNumber() + 1, - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounterBefore.toNumber() + 1, - amount: collateralToDeposit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - - assert.equal( - marginPoolBalanceAfter.minus(marginPoolBalanceBefore).toString(), - collateralToDeposit.toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - senderBalanceBefore.minus(senderBalanceAfter).toString(), - collateralToDeposit.toString(), - 'Sender collateral asset balance mismatch', - ) - }) - - it('should revert burning an expired short otoken', async () => { - // increment time after expiredLongOtoken expiry - await time.increase(3601) // increase time with one hour in seconds - - const vaultId = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const shortAmountToBurn = new BigNumber('1') - const actionArgs = [ - { - actionType: ActionType.BurnShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: expiredShortOtoken.address, - vaultId: vaultId.toNumber(), - amount: shortAmountToBurn.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - - assert.equal( - await controllerProxy.hasExpired(expiredShortOtoken.address), - true, - 'Long otoken is not expired yet', - ) - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C26') - }) - - it('should revert minting an expired short otoken', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToDeposit = new BigNumber(await expiredShortOtoken.strikePrice()).dividedBy(100) - const amountToMint = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: expiredShortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOperator1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C24') - }) - - it('should revert withdraw collateral from a vault with an expired short otoken', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToWithdraw = createTokenAmount(10, usdcDecimals) - const actionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToWithdraw, - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C22') - }) - }) - }) - }) - - describe('Redeem', () => { - let shortOtoken: MockOtokenInstance - let fakeOtoken: MockOtokenInstance - let finalMarginPool: string - - before(async () => { - const expiryTime = new BigNumber(60 * 60 * 24) // after 1 day - - shortOtoken = await MockOtoken.new() - // init otoken - await shortOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - - fakeOtoken = await MockOtoken.new() - // init otoken - await fakeOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - - // whitelist short otoken to be used in the protocol - await whitelist.whitelistOtoken(shortOtoken.address, { from: owner }) - // open new vault, mintnaked short, sell it to holder 1 - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(100) - const amountToMint = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - await borrowableMarginPool.setOTokenBuyerWhitelistedStatus(holder1, true, { from: owner }) - finalMarginPool = - !(await borrowableMarginPool.isWhitelistedOTokenBuyer(holder1)) || - new BigNumber(await usdc.balanceOf(borrowableMarginPool.address)).isLessThan(collateralToDeposit) - ? marginPool.address - : borrowableMarginPool.address - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - // transfer minted short otoken to hodler` - await shortOtoken.transfer(holder1, amountToMint.toString(), { from: accountOwner1 }) - }) - - it('should revert exercising non-whitelisted otoken', async () => { - const shortAmountToBurn = new BigNumber('1') - const actionArgs = [ - { - actionType: ActionType.Redeem, - owner: ZERO_ADDR, - secondAddress: holder1, - asset: fakeOtoken.address, - vaultId: '0', - amount: shortAmountToBurn.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: holder1 }), 'C27') - }) - - it('should revert exercising un-expired otoken', async () => { - const shortAmountToBurn = new BigNumber('1') - const actionArgs = [ - { - actionType: ActionType.Redeem, - owner: ZERO_ADDR, - secondAddress: holder1, - asset: shortOtoken.address, - vaultId: '0', - amount: shortAmountToBurn.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - - assert.equal(await controllerProxy.hasExpired(shortOtoken.address), false, 'Short otoken has already expired') - - await expectRevert(controllerProxy.operate(actionArgs, { from: holder1 }), 'C28') - }) - - it('should revert exercising after expiry, when underlying price is not finalized yet', async () => { - // past time after expiry - await time.increase(60 * 61 * 24) // increase time with one hour in seconds - // set price in Oracle Mock, 150$ at expiry, expire ITM - await oracle.setExpiryPriceFinalizedAllPeiodOver( - await shortOtoken.underlyingAsset(), - new BigNumber(await shortOtoken.expiryTimestamp()), - createTokenAmount(150), - true, - ) - // set it as not finalized in mock - await oracle.setIsDisputePeriodOver( - await shortOtoken.underlyingAsset(), - new BigNumber(await shortOtoken.expiryTimestamp()), - false, - ) - - await oracle.setExpiryPriceFinalizedAllPeiodOver( - await shortOtoken.strikeAsset(), - new BigNumber(await shortOtoken.expiryTimestamp()), - createTokenAmount(1), - true, - ) - - const shortAmountToBurn = new BigNumber('1') - const actionArgs = [ - { - actionType: ActionType.Redeem, - owner: ZERO_ADDR, - secondAddress: holder1, - asset: shortOtoken.address, - vaultId: '0', - amount: shortAmountToBurn.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - - assert.equal(await controllerProxy.hasExpired(shortOtoken.address), true, 'Short otoken is not expired yet') - - await expectRevert(controllerProxy.operate(actionArgs, { from: holder1 }), 'C29') - }) - - it('should revert exercising if cash value receiver address in equal to address zero', async () => { - // set it as finalized in mock - await oracle.setIsDisputePeriodOver( - await shortOtoken.underlyingAsset(), - new BigNumber(await shortOtoken.expiryTimestamp()), - true, - ) - - const shortAmountToBurn = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.Redeem, - owner: ZERO_ADDR, - secondAddress: ZERO_ADDR, - asset: shortOtoken.address, - vaultId: '0', - amount: shortAmountToBurn, - index: '0', - data: ZERO_ADDR, - }, - ] - - assert.equal(await controllerProxy.hasExpired(shortOtoken.address), true, 'Short otoken is not expired yet') - - await expectRevert(controllerProxy.operate(actionArgs, { from: holder1 }), 'A14') - }) - - it('should redeem after expiry + price is finalized', async () => { - const shortAmountToBurn = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.Redeem, - owner: ZERO_ADDR, - secondAddress: holder1, - asset: shortOtoken.address, - vaultId: '0', - amount: shortAmountToBurn, - index: '0', - data: ZERO_ADDR, - }, - ] - assert.equal(await controllerProxy.hasExpired(shortOtoken.address), true, 'Short otoken is not expired yet') - - const payout = createTokenAmount(50, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(holder1)) - const senderShortBalanceBefore = new BigNumber(await shortOtoken.balanceOf(holder1)) - - await controllerProxy.operate(actionArgs, { from: holder1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(holder1)) - const senderShortBalanceAfter = new BigNumber(await shortOtoken.balanceOf(holder1)) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - payout.toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - senderBalanceAfter.minus(senderBalanceBefore).toString(), - payout.toString(), - 'Sender collateral asset balance mismatch', - ) - assert.equal( - senderShortBalanceBefore.minus(senderShortBalanceAfter).toString(), - shortAmountToBurn.toString(), - ' Burned short otoken amount mismatch', - ) - }) - - it('should redeem call option correctly', async () => { - const expiry = new BigNumber(await time.latest()).plus(new BigNumber(60 * 60)).toNumber() - const call: MockOtokenInstance = await MockOtoken.new() - await call.init( - addressBook.address, - weth.address, - usdc.address, - weth.address, - createTokenAmount(200), - expiry, - false, - ) - - await whitelist.whitelistOtoken(call.address) - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const amountCollateral = createTokenAmount(1, wethDecimals) - await weth.mint(accountOwner1, amountCollateral) - await weth.approve(finalMarginPool, amountCollateral, { from: accountOwner1 }) - const amountOtoken = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: weth.address, - vaultId: vaultCounter.toNumber(), - amount: amountCollateral, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: call.address, - vaultId: vaultCounter.toNumber(), - amount: amountOtoken, - index: '0', - data: ZERO_ADDR, - }, - ] - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - await call.transfer(holder1, amountOtoken, { from: accountOwner1 }) - - await time.increaseTo(expiry + 10) - await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry, createTokenAmount(400), true) - await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, createTokenAmount(1), true) - const redeemArgs = [ - { - actionType: ActionType.Redeem, - owner: ZERO_ADDR, - secondAddress: holder1, - asset: call.address, - vaultId: '0', - amount: amountOtoken, - index: '0', - data: ZERO_ADDR, - }, - ] - - const expectedPayout = createTokenAmount(0.5, wethDecimals) - - const userBalanceBefore = new BigNumber(await weth.balanceOf(holder1)) - await controllerProxy.operate(redeemArgs, { from: holder1 }) - const userBalanceAfter = new BigNumber(await weth.balanceOf(holder1)) - assert.equal(userBalanceAfter.minus(userBalanceBefore).toString(), expectedPayout) - }) - - it('should revert redeem option if collateral is different from underlying, and collateral price is not finalized', async () => { - const expiry = new BigNumber(await time.latest()).plus(new BigNumber(60 * 60)).toNumber() - - await whitelist.whitelistCollateral(weth2.address) - const call: MockOtokenInstance = await MockOtoken.new() - await call.init( - addressBook.address, - weth.address, - usdc.address, - weth2.address, - createTokenAmount(200), - expiry, - false, - ) - - await oracle.setRealTimePrice(weth.address, createTokenAmount(400)) - await oracle.setRealTimePrice(weth2.address, createTokenAmount(400)) - - await whitelist.whitelistOtoken(call.address) - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const amountCollateral = createTokenAmount(1, wethDecimals) - await weth2.mint(accountOwner1, amountCollateral) - await weth2.approve(finalMarginPool, amountCollateral, { from: accountOwner1 }) - - const amountOtoken = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: call.address, - vaultId: vaultCounter.toNumber(), - amount: amountOtoken, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: weth2.address, - vaultId: vaultCounter.toNumber(), - amount: amountCollateral, - index: '0', - data: ZERO_ADDR, - }, - ] - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - await call.transfer(holder1, amountOtoken, { from: accountOwner1 }) - - await time.increaseTo(expiry + 10) - await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry, createTokenAmount(400), true) - await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, createTokenAmount(1), true) - - const redeemArgs = [ - { - actionType: ActionType.Redeem, - owner: ZERO_ADDR, - secondAddress: holder1, - asset: call.address, - vaultId: '0', - amount: amountOtoken, - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(redeemArgs, { from: holder1 }), 'C29') - }) - - describe('Redeem multiple Otokens', () => { - let firstOtoken: MockOtokenInstance - let secondOtoken: MockOtokenInstance - - before(async () => { - const expiryTime = new BigNumber(60 * 60 * 24) // after 1 day - - firstOtoken = await MockOtoken.new() - secondOtoken = await MockOtoken.new() - - const expiry = new BigNumber(await time.latest()).plus(expiryTime) - // init otoken - await firstOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - expiry, - true, - ) - await secondOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - expiry, - true, - ) - // whitelist otoken to be used in the protocol - await whitelist.whitelistOtoken(firstOtoken.address, { from: owner }) - await whitelist.whitelistOtoken(secondOtoken.address, { from: owner }) - - // open new vault, mint naked short, sell it to holder 1 - const firstCollateralToDeposit = new BigNumber(await firstOtoken.strikePrice()).dividedBy(100) - const secondCollateralToDeposit = new BigNumber(await secondOtoken.strikePrice()).dividedBy(100) - const amountToMint = createTokenAmount(1) - let vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - let actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: firstOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: firstCollateralToDeposit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - await usdc.approve(finalMarginPool, firstCollateralToDeposit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: secondOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: secondCollateralToDeposit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - await usdc.approve(finalMarginPool, firstCollateralToDeposit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - // transfer minted short otoken to hodler - await firstOtoken.transfer(holder1, amountToMint, { from: accountOwner1 }) - await secondOtoken.transfer(holder1, amountToMint, { from: accountOwner1 }) - }) - - it('should redeem multiple Otokens in one transaction', async () => { - // past time after expiry - await time.increase(60 * 61 * 24) - // set price in Oracle Mock, 150$ at expiry, expire ITM - await oracle.setExpiryPriceFinalizedAllPeiodOver( - await firstOtoken.underlyingAsset(), - new BigNumber(await firstOtoken.expiryTimestamp()), - createTokenAmount(150), - true, - ) - await oracle.setExpiryPriceFinalizedAllPeiodOver( - await secondOtoken.underlyingAsset(), - new BigNumber(await secondOtoken.expiryTimestamp()), - createTokenAmount(150), - true, - ) - - await oracle.setExpiryPriceFinalizedAllPeiodOver( - await firstOtoken.strikeAsset(), - new BigNumber(await firstOtoken.expiryTimestamp()), - createTokenAmount(1), - true, - ) - await oracle.setExpiryPriceFinalizedAllPeiodOver( - await secondOtoken.strikeAsset(), - new BigNumber(await firstOtoken.expiryTimestamp()), - createTokenAmount(1), - true, - ) - - const amountToRedeem = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.Redeem, - owner: ZERO_ADDR, - secondAddress: holder1, - asset: firstOtoken.address, - vaultId: '0', - amount: amountToRedeem, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.Redeem, - owner: ZERO_ADDR, - secondAddress: holder1, - asset: secondOtoken.address, - vaultId: '0', - amount: amountToRedeem, - index: '0', - data: ZERO_ADDR, - }, - ] - - const payout = createTokenAmount(100, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(holder1)) - - await controllerProxy.operate(actionArgs, { from: holder1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(holder1)) - const senderFirstBalanceAfter = new BigNumber(await firstOtoken.balanceOf(holder1)) - const senderSecondBalanceAfter = new BigNumber(await secondOtoken.balanceOf(holder1)) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - payout.toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - senderBalanceAfter.minus(senderBalanceBefore).toString(), - payout.toString(), - 'Sender collateral asset balance mismatch', - ) - assert.equal(senderFirstBalanceAfter.toString(), '0', ' Burned first otoken amount mismatch') - assert.equal(senderSecondBalanceAfter.toString(), '0', ' Burned first otoken amount mismatch') - }) - }) - }) - - describe('Settle vault', () => { - let shortOtoken: MockOtokenInstance - - before(async () => { - const expiryTime = new BigNumber(60 * 60 * 24) // after 1 day - - shortOtoken = await MockOtoken.new() - // init otoken - await shortOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - // whitelist otoken to be used in the protocol - await whitelist.whitelistOtoken(shortOtoken.address, { from: owner }) - // open new vault, mint naked short, sell it to holder 1 - const collateralToDespoit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(100) - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDespoit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - await usdc.approve(finalMarginPool, collateralToDespoit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - }) - - it('should revert settling a vault that have no long or short otoken', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const actionArgs = [ - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C30') - }) - - it('should revert settling vault before expiry', async () => { - // mint token in vault before - const amountToMint = createTokenAmount(1) - let vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - let actionArgs = [ - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - ] - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - await shortOtoken.transfer(holder1, amountToMint, { from: accountOwner1 }) - - vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - actionArgs = [ - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C31') - }) - - it('should revert settling an invalid vault', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const actionArgs = [ - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.plus(10000).toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C35') - }) - - it('should revert settling after expiry when price is not finalized', async () => { - // past time after expiry - await time.increase(60 * 61 * 24) // increase time with one hour in seconds - // set price in Oracle Mock, 150$ at expiry, expire ITM - const expiry = new BigNumber(await shortOtoken.expiryTimestamp()) - await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry, createTokenAmount(150), true) - // set it as not finalized in mock - await oracle.setIsFinalized( - await shortOtoken.underlyingAsset(), - new BigNumber(await shortOtoken.expiryTimestamp()), - false, - ) - await oracle.setIsDisputePeriodOver( - await shortOtoken.underlyingAsset(), - new BigNumber(await shortOtoken.expiryTimestamp()), - false, - ) - - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const actionArgs = [ - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - assert.equal(await controllerProxy.hasExpired(shortOtoken.address), true, 'Short otoken is not expired yet') - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C29') - }) - - it('should settle ITM otoken after expiry + price is finalized', async () => { - const expiry = new BigNumber(await shortOtoken.expiryTimestamp()) - await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry, createTokenAmount(150), true) - await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, createTokenAmount(1), true) - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - const actionArgs = [ - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - const payout = createTokenAmount(150, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - const proceed = await controllerProxy.getProceed(accountOwner1, vaultCounter) - - assert.equal(payout, proceed.toString()) - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - payout.toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - senderBalanceAfter.minus(senderBalanceBefore).toString(), - payout.toString(), - 'Sender collateral asset balance mismatch', - ) - }) - - it('should settle vault with only long otokens in it', async () => { - const stirkePrice = 250 - const expiry = new BigNumber(await time.latest()).plus(86400) - const longOtoken: MockOtokenInstance = await MockOtoken.new() - // create a new otoken - await longOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createScaledNumber(stirkePrice), - expiry, - true, - ) - - await whitelist.whitelistOtoken(longOtoken.address) - - // mint some long otokens, (so we can put it as long) - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - const longAmount = createTokenAmount(1) - const collateralAmount = createTokenAmount(stirkePrice, usdcDecimals) - const mintArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: longAmount, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralAmount, - index: '0', - data: ZERO_ADDR, - }, - ] - await usdc.approve(finalMarginPool, collateralAmount, { from: accountOwner1 }) - await controllerProxy.operate(mintArgs, { from: accountOwner1 }) - // Use the newly minted otoken as long and put it in a new vault - const newVaultId = vaultCounter.toNumber() + 1 - - const newVaultArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: newVaultId, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositLongOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: longOtoken.address, - vaultId: newVaultId, - amount: longAmount, - index: '0', - data: ZERO_ADDR, - }, - ] - await longOtoken.approve(finalMarginPool, longAmount, { from: accountOwner1 }) - await whitelist.whitelistOtoken(longOtoken.address) - await controllerProxy.operate(newVaultArgs, { from: accountOwner1 }) - // go to expiry - await time.increaseTo(expiry.toNumber() + 10) - const ethPriceAtExpiry = 200 - await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, createScaledNumber(1), true) - await oracle.setExpiryPriceFinalizedAllPeiodOver( - weth.address, - expiry, - createScaledNumber(ethPriceAtExpiry), - true, - ) - // settle the secont vault (with only long otoken in it) - const settleArgs = [ - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: newVaultId, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - const expectedPayout = new BigNumber(createTokenAmount(stirkePrice - ethPriceAtExpiry, usdcDecimals)) - const ownerUSDCBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - const poolOtokenBefore = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - - const amountPayout = await controllerProxy.getProceed(accountOwner1, newVaultId) - - assert.equal(amountPayout.toString(), expectedPayout.toString(), 'payout calculation mismatch') - await controllerProxy.operate(settleArgs, { from: accountOwner1 }) - const ownerUSDCBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - const poolOtokenAfter = new BigNumber(await longOtoken.balanceOf(finalMarginPool)) - assert.equal( - ownerUSDCBalanceAfter.toString(), - ownerUSDCBalanceBefore.plus(amountPayout).toString(), - 'settle long vault payout mismatch', - ) - assert.equal( - poolOtokenAfter.toString(), - poolOtokenBefore.minus(new BigNumber(longAmount)).toString(), - 'settle long vault otoken mismatch', - ) - }) - - describe('Settle multiple vaults ATM and OTM', () => { - let firstShortOtoken: MockOtokenInstance - let secondShortOtoken: MockOtokenInstance - - before(async () => { - let expiryTime = new BigNumber(60 * 60 * 24) // after 1 day - - firstShortOtoken = await MockOtoken.new() - await firstShortOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - // whitelist otoken to be used in the protocol - await whitelist.whitelistOtoken(firstShortOtoken.address, { from: owner }) - // open new vault, mint naked short, sell it to holder 1 - let collateralToDespoit = createTokenAmount(200, usdcDecimals) - let amountToMint = createTokenAmount(1) - let vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - let actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: firstShortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint.toString(), - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDespoit, - index: '0', - data: ZERO_ADDR, - }, - ] - await usdc.approve(finalMarginPool, collateralToDespoit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - expiryTime = new BigNumber(60 * 60 * 24 * 2) // after 1 day - secondShortOtoken = await MockOtoken.new() - await secondShortOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - // whitelist otoken to be used in the protocol - await whitelist.whitelistOtoken(secondShortOtoken.address, { from: owner }) - // open new vault, mint naked short, sell it to holder 1 - collateralToDespoit = createTokenAmount(200, usdcDecimals) - amountToMint = createTokenAmount(1) - vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - - actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: secondShortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint.toString(), - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDespoit, - index: '0', - data: ZERO_ADDR, - }, - ] - await usdc.approve(finalMarginPool, collateralToDespoit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - }) - - it('should settle multiple vaults in one transaction (ATM,OTM)', async () => { - await time.increaseTo(new BigNumber(await secondShortOtoken.expiryTimestamp()).plus(1000).toString()) - const expiry = new BigNumber(await firstShortOtoken.expiryTimestamp()) - const expiry2 = new BigNumber(await secondShortOtoken.expiryTimestamp()) - await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry, createTokenAmount(200), true) - await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, createTokenAmount(1), true) - await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry2, createTokenAmount(200), true) - await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry2, createTokenAmount(1), true) - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const actionArgs = [ - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: secondShortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: firstShortOtoken.address, - vaultId: vaultCounter.minus(1).toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - const payout = createTokenAmount(400, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - - controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - payout, - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - senderBalanceAfter.minus(senderBalanceBefore).toString(), - payout, - 'Sender collateral asset balance mismatch', - ) - }) - }) - }) - - describe('Check if price is finalized', () => { - let expiredOtoken: MockOtokenInstance - let expiry: BigNumber - - before(async () => { - expiry = new BigNumber(await time.latest()) - expiredOtoken = await MockOtoken.new() - // init otoken - await expiredOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()), - true, - ) - - // set finalized - await oracle.setIsFinalized(weth.address, expiry, true) - await oracle.setIsDisputePeriodOver(weth.address, expiry, true) - }) - - it('should return false when price is pushed and dispute period not over yet', async () => { - const priceMock = new BigNumber('200') - - // Mock oracle returned data. - await oracle.setIsLockingPeriodOver(weth.address, expiry, true) - await oracle.setIsDisputePeriodOver(weth.address, expiry, false) - await oracle.setExpiryPrice(weth.address, expiry, priceMock) - - const underlying = await expiredOtoken.underlyingAsset() - const strike = await expiredOtoken.strikeAsset() - const collateral = await expiredOtoken.collateralAsset() - const expiryTimestamp = await expiredOtoken.expiryTimestamp() - - const expectedResult = false - assert.equal( - await controllerProxy.canSettleAssets(underlying, strike, collateral, expiryTimestamp), - expectedResult, - 'Price is not finalized because dispute period is not over yet', - ) - assert.equal( - await controllerProxy.isSettlementAllowed(expiredOtoken.address), - expectedResult, - 'Price is not finalized', - ) - }) - - it('should return true when price is finalized', async () => { - expiredOtoken = await MockOtoken.new() - const expiry = new BigNumber(await time.latest()) - // init otoken - await expiredOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - expiry, - true, - ) - - // Mock oracle: dispute periodd over, set price to 200. - const priceMock = new BigNumber('200') - await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry, priceMock, true) - await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, createTokenAmount(1), true) - - const underlying = await expiredOtoken.underlyingAsset() - const strike = await expiredOtoken.strikeAsset() - const collateral = await expiredOtoken.collateralAsset() - const expiryTimestamp = await expiredOtoken.expiryTimestamp() - - const expectedResult = true - assert.equal( - await controllerProxy.canSettleAssets(underlying, strike, collateral, expiryTimestamp), - expectedResult, - 'Price is not finalized', - ) - assert.equal( - await controllerProxy.isSettlementAllowed(expiredOtoken.address), - expectedResult, - 'Price is not finalized', - ) - }) - }) - - describe('Expiry', () => { - it('should return false for non expired otoken', async () => { - const otoken: MockOtokenInstance = await MockOtoken.new() - await otoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(60000 * 60000), - true, - ) - - assert.equal(await controllerProxy.hasExpired(otoken.address), false, 'Otoken expiry check mismatch') - }) - - it('should return true for expired otoken', async () => { - // Otoken deployment - const expiredOtoken = await MockOtoken.new() - // init otoken - await expiredOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - 1219835219, - true, - ) - - assert.equal(await controllerProxy.hasExpired(expiredOtoken.address), true, 'Otoken expiry check mismatch') - }) - }) - - describe('Call action', () => { - let callTester: CallTesterInstance - - before(async () => { - callTester = await CallTester.new() - }) - - it('should call any arbitrary destination address when restriction is not activated', async () => { - //whitelist callee before call action - await whitelist.whitelistCallee(callTester.address, { from: owner }) - - const actionArgs = [ - { - actionType: ActionType.Call, - owner: ZERO_ADDR, - secondAddress: callTester.address, - asset: ZERO_ADDR, - vaultId: '0', - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - expectEvent(await controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'CallExecuted', { - from: accountOwner1, - to: callTester.address, - data: ZERO_ADDR, - }) - }) - - it('should revert activating call action restriction from non-owner', async () => { - await expectRevert( - controllerProxy.setCallRestriction(true, { from: random }), - 'Ownable: caller is not the owner', - ) - }) - - it('should revert calling any arbitrary address when call restriction is activated', async () => { - const arbitraryTarget: CallTesterInstance = await CallTester.new() - - const actionArgs = [ - { - actionType: ActionType.Call, - owner: ZERO_ADDR, - secondAddress: arbitraryTarget.address, - asset: ZERO_ADDR, - vaultId: '0', - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C3') - }) - - it('should call whitelisted callee address when restriction is activated', async () => { - // whitelist callee - await whitelist.whitelistCallee(callTester.address, { from: owner }) - - const actionArgs = [ - { - actionType: ActionType.Call, - owner: ZERO_ADDR, - secondAddress: callTester.address, - asset: ZERO_ADDR, - vaultId: '0', - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - expectEvent(await controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'CallExecuted', { - from: accountOwner1, - to: callTester.address, - data: ZERO_ADDR, - }) - }) - - it('should deactivate call action restriction from owner', async () => { - await controllerProxy.setCallRestriction(false, { from: owner }) - - assert.equal(await controllerProxy.callRestricted(), false, 'Call action restriction deactivation failed') - }) - }) - - describe('Sync vault latest update timestamp', () => { - it('should update vault latest update timestamp', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const timestampBefore = new BigNumber( - (await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter.toNumber()))[2], - ) - - await controllerProxy.sync(accountOwner1, vaultCounter.toNumber(), { from: random }) - - const timestampAfter = new BigNumber( - (await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter.toNumber()))[2], - ) - assert.isAbove( - timestampAfter.toNumber(), - timestampBefore.toNumber(), - 'Vault latest update timestamp did not sync', - ) - }) - }) - - describe('Interact with Otoken implementation v1.0.0', () => { - let shortOtokenV1: OtokenImplV1Instance - - before(async () => { - const expiryTime = new BigNumber(60 * 60 * 24) // after 1 day - - shortOtokenV1 = await OtokenImplV1.new() - // init otoken - await shortOtokenV1.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - // whitelist otoken to be used in the protocol - await whitelist.whitelistOtoken(shortOtokenV1.address, { from: owner }) - // open new vault, mint naked short, sell it to holder 1 - const collateralToDespoit = new BigNumber(await shortOtokenV1.strikePrice()).dividedBy(100) - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - const amountToMint = createTokenAmount(1) - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDespoit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtokenV1.address, - vaultId: vaultCounter.toNumber(), - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - ] - await usdc.approve(finalMarginPool, collateralToDespoit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - //transfer to holder - await shortOtokenV1.transfer(holder1, amountToMint, { from: accountOwner1 }) - }) - - it('should settle v1 Otoken implementation', async () => { - // past time after expiry - await time.increase(60 * 61 * 24) // increase time with one hour in seconds - - const expiry = new BigNumber(await shortOtokenV1.expiryTimestamp()) - await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry, createTokenAmount(150), true) - await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, createTokenAmount(1), true) - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const actionArgs = [ - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtokenV1.address, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - const payout = createTokenAmount(150, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - const proceed = await controllerProxy.getProceed(accountOwner1, vaultCounter) - - assert.equal(payout, proceed.toString()) - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - payout.toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - senderBalanceAfter.minus(senderBalanceBefore).toString(), - payout.toString(), - 'Sender collateral asset balance mismatch', - ) - }) - - it('should redeem v1 Otoken implementation', async () => { - const redeemArgs = [ - { - actionType: ActionType.Redeem, - owner: ZERO_ADDR, - secondAddress: holder1, - asset: shortOtokenV1.address, - vaultId: '0', - amount: createTokenAmount(1), - index: '0', - data: ZERO_ADDR, - }, - ] - - const expectedPayout = createTokenAmount(50, usdcDecimals) - - const userBalanceBefore = new BigNumber(await usdc.balanceOf(holder1)) - await controllerProxy.operate(redeemArgs, { from: holder1 }) - const userBalanceAfter = new BigNumber(await usdc.balanceOf(holder1)) - assert.equal(userBalanceAfter.minus(userBalanceBefore).toString(), expectedPayout) - }) - }) - - describe('Pause mechanism', () => { - let shortOtoken: MockOtokenInstance - - before(async () => { - const vaultCounterBefore = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const expiryTime = new BigNumber(60 * 60) // after 1 hour - shortOtoken = await MockOtoken.new() - // init otoken - await shortOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - - // whitelist otoken to be minted - await whitelist.whitelistOtoken(shortOtoken.address, { from: owner }) - - const collateralToDeposit = createTokenAmount(200, usdcDecimals) - const amountToMint = createTokenAmount(1) // mint 1 otoken - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounterBefore.toNumber() + 1, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounterBefore.toNumber() + 1, - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounterBefore.toNumber() + 1, - amount: collateralToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - }) - - it('should revert set pauser address from non-owner', async () => { - await expectRevert( - controllerProxy.setPartialPauser(partialPauser, { from: random }), - 'Ownable: caller is not the owner', - ) - }) - - it('should set pauser address', async () => { - await controllerProxy.setPartialPauser(partialPauser, { from: owner }) - assert.equal(await controllerProxy.partialPauser(), partialPauser, 'pauser address mismatch') - }) - - it('should revert when pausing the system from address other than pauser', async () => { - await expectRevert(controllerProxy.setSystemPartiallyPaused(true, { from: random }), 'C2') - }) - - it('should pause system', async () => { - const stateBefore = await controllerProxy.systemPartiallyPaused() - assert.equal(stateBefore, false, 'System already paused') - - await controllerProxy.setSystemPartiallyPaused(true, { from: partialPauser }) - - const stateAfter = await controllerProxy.systemPartiallyPaused() - assert.equal(stateAfter, true, 'System not paused') - }) - - it('should revert opening a vault when system is partially paused', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber() + 1, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C4') - }) - - it('should revert depositing collateral when system is partially paused', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(1e8) - const actionArgs = [ - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber() + 1, - amount: collateralToDeposit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C4') - }) - - it('should revert minting short otoken when system is partially paused', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(1e8) - const actionArgs = [ - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: '1', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C4') - }) - - it('should revert withdrawing collateral when system is partially paused', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const collateralToWithdraw = new BigNumber(await shortOtoken.strikePrice()).dividedBy(100) - const actionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToWithdraw.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C4') - }) - - it('should revert burning short otoken when system is partially paused', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const actionArgs = [ - { - actionType: ActionType.BurnShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: '1', - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C4') - }) - - it('should settle vault when system is partially paused', async () => { - // past time after expiry - await time.increase(60 * 61) // increase time with one hour in seconds - // set price in Oracle Mock, 150$ at expiry, expire ITM - const expiry = new BigNumber(await shortOtoken.expiryTimestamp()) - await oracle.setExpiryPriceFinalizedAllPeiodOver(weth.address, expiry, createTokenAmount(150), true) - await oracle.setExpiryPriceFinalizedAllPeiodOver(usdc.address, expiry, createTokenAmount(1), true) - - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const actionArgs = [ - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - const payout = createTokenAmount(150, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(accountOwner1)) - - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(accountOwner1)) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - payout.toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - senderBalanceAfter.minus(senderBalanceBefore).toString(), - payout.toString(), - 'Seller collateral asset balance mismatch', - ) - }) - - it('should redeem when system is partially paused', async () => { - const amountToRedeem = createTokenAmount(1) - // transfer to holder - await shortOtoken.transfer(holder1, amountToRedeem, { from: accountOwner1 }) - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - const actionArgs = [ - { - actionType: ActionType.Redeem, - owner: ZERO_ADDR, - secondAddress: holder1, - asset: shortOtoken.address, - vaultId: '0', - amount: amountToRedeem, - index: '0', - data: ZERO_ADDR, - }, - ] - assert.equal(await controllerProxy.hasExpired(shortOtoken.address), true, 'Short otoken is not expired yet') - - const payout = createTokenAmount(50, usdcDecimals) - const marginPoolBalanceBefore = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceBefore = new BigNumber(await usdc.balanceOf(holder1)) - const senderShortBalanceBefore = new BigNumber(await shortOtoken.balanceOf(holder1)) - - await controllerProxy.operate(actionArgs, { from: holder1 }) - - const marginPoolBalanceAfter = new BigNumber(await usdc.balanceOf(finalMarginPool)) - const senderBalanceAfter = new BigNumber(await usdc.balanceOf(holder1)) - const senderShortBalanceAfter = new BigNumber(await shortOtoken.balanceOf(holder1)) - - assert.equal( - marginPoolBalanceBefore.minus(marginPoolBalanceAfter).toString(), - payout.toString(), - 'Margin pool collateral asset balance mismatch', - ) - assert.equal( - senderBalanceAfter.minus(senderBalanceBefore).toString(), - payout.toString(), - 'Sender collateral asset balance mismatch', - ) - assert.equal( - senderShortBalanceBefore.minus(senderShortBalanceAfter).toString(), - amountToRedeem.toString(), - ' Burned short otoken amount mismatch', - ) - }) - }) - - describe('Full Pause', () => { - let shortOtoken: MockOtokenInstance - - before(async () => { - // deactivate pausing mechanism - await controllerProxy.setSystemPartiallyPaused(false, { from: partialPauser }) - - const vaultCounterBefore = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - - const expiryTime = new BigNumber(60 * 60) // after 1 hour - shortOtoken = await MockOtoken.new() - // init otoken - await shortOtoken.init( - addressBook.address, - weth.address, - usdc.address, - usdc.address, - createTokenAmount(200), - new BigNumber(await time.latest()).plus(expiryTime), - true, - ) - - // whitelist otoken to be minted - await whitelist.whitelistOtoken(shortOtoken.address, { from: owner }) - - const collateralToDeposit = createTokenAmount(200, usdcDecimals) - const amountToMint = createTokenAmount(1) // mint 1 otoken - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounterBefore.toNumber() + 1, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounterBefore.toNumber() + 1, - amount: amountToMint, - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounterBefore.toNumber() + 1, - amount: collateralToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await controllerProxy.operate(actionArgs, { from: accountOwner1 }) - }) - - it('should revert set fullPauser address from non-owner', async () => { - await expectRevert( - controllerProxy.setFullPauser(fullPauser, { from: random }), - 'Ownable: caller is not the owner', - ) - }) - - it('should set fullPauser', async () => { - await controllerProxy.setFullPauser(fullPauser, { from: owner }) - assert.equal(await controllerProxy.fullPauser(), fullPauser, 'Full pauser wrong') - }) - - it('should revert when triggering full pause from address other than pauser', async () => { - await expectRevert(controllerProxy.setSystemFullyPaused(true, { from: random }), 'C1') - }) - - it('should trigger full pause', async () => { - const stateBefore = await controllerProxy.systemFullyPaused() - assert.equal(stateBefore, false, 'System already in full pause state') - - await controllerProxy.setSystemFullyPaused(true, { from: fullPauser }) - - const stateAfter = await controllerProxy.systemFullyPaused() - assert.equal(stateAfter, true, 'System not in full pause state') - }) - - it('should revert opening a vault when system is in full pause state', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const actionArgs = [ - { - actionType: ActionType.OpenVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: ZERO_ADDR, - vaultId: vaultCounter.toNumber() + 1, - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), '.') - }) - - it('should revert depositing collateral when system is in full pause state', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(1e8) - const actionArgs = [ - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber() + 1, - amount: collateralToDeposit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C5') - }) - - it('should revert minting short otoken when system is in full pause state', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const collateralToDeposit = new BigNumber(await shortOtoken.strikePrice()).dividedBy(1e8) - const actionArgs = [ - { - actionType: ActionType.MintShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: '1', - index: '0', - data: ZERO_ADDR, - }, - { - actionType: ActionType.DepositCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C5') - }) - - it('should revert withdrawing collateral when system is in full pause state', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const collateralToWithdraw = new BigNumber(await shortOtoken.strikePrice()).dividedBy(1e8) - const actionArgs = [ - { - actionType: ActionType.WithdrawCollateral, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToWithdraw.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C5') - }) - - it('should revert burning short otoken when system is in full pause state', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const actionArgs = [ - { - actionType: ActionType.BurnShortOption, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: '1', - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C5') - }) - - it('should revert settling vault when system is in full pause state', async () => { - // past time after expiry - await time.increase(60 * 61) // increase time with one hour in seconds - // set price in Oracle Mock, 150$ at expiry, expire ITM - await oracle.setExpiryPrice( - await shortOtoken.underlyingAsset(), - new BigNumber(await shortOtoken.expiryTimestamp()), - createTokenAmount(150), - ) - // set it as finalized in mock - await oracle.setIsFinalized( - await shortOtoken.underlyingAsset(), - new BigNumber(await shortOtoken.expiryTimestamp()), - true, - ) - await oracle.setIsDisputePeriodOver( - await shortOtoken.underlyingAsset(), - new BigNumber(await shortOtoken.expiryTimestamp()), - true, - ) - - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const actionArgs = [ - { - actionType: ActionType.SettleVault, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: shortOtoken.address, - vaultId: vaultCounter.toNumber(), - amount: '0', - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C5') - }) - - it('should revert redeem when system is in full pause state', async () => { - const shortAmountToBurn = new BigNumber('1') - // transfer to holder - await shortOtoken.transfer(holder1, shortAmountToBurn, { from: accountOwner1 }) - - const actionArgs = [ - { - actionType: ActionType.Redeem, - owner: ZERO_ADDR, - secondAddress: holder1, - asset: shortOtoken.address, - vaultId: '0', - amount: shortAmountToBurn.toNumber(), - index: '0', - data: ZERO_ADDR, - }, - ] - - await expectRevert(controllerProxy.operate(actionArgs, { from: accountOwner1 }), 'C5') - }) - }) - - describe('Donate to pool v1', () => { - it('it should donate to margin pool', async () => { - const amountToDonate = createTokenAmount(10, usdcDecimals) - const storedBalanceBefore = new BigNumber(await marginPool.getStoredBalance(usdc.address)) - - await usdc.approve(marginPool.address, amountToDonate, { from: donor }) - await controllerProxy.donate(usdc.address, amountToDonate, { from: donor }) - - const storedBalanceAfter = new BigNumber(await marginPool.getStoredBalance(usdc.address)) - - assert.equal( - storedBalanceAfter.minus(storedBalanceBefore).toString(), - amountToDonate, - 'Donated amount mismatch', - ) - }) - }) - - describe('Donate to borrowable pool', () => { - it('it should donate to margin pool v2', async () => { - const amountToDonate = createTokenAmount(10, usdcDecimals) - const storedBalanceBefore = new BigNumber(await borrowableMarginPool.getStoredBalance(usdc.address)) - - await usdc.approve(borrowableMarginPool.address, amountToDonate, { from: donor }) - await controllerProxy.donateBorrowablePool(usdc.address, amountToDonate, { from: donor }) - - const storedBalanceAfter = new BigNumber(await borrowableMarginPool.getStoredBalance(usdc.address)) - - assert.equal( - storedBalanceAfter.minus(storedBalanceBefore).toString(), - amountToDonate, - 'Donated amount mismatch', - ) - }) - }) - - describe('Refresh configuration', () => { - it('should revert refreshing configuration from address other than owner', async () => { - await expectRevert(controllerProxy.refreshConfiguration({ from: random }), 'Ownable: caller is not the owner') - }) - - it('should refresh configuratiom', async () => { - // update modules - const oracle = await MockOracle.new(addressBook.address, { from: owner }) - const calculator = await MarginCalculator.new(addressBook.address, { from: owner }) - const marginPool = await MarginPool.new(addressBook.address, { from: owner }) - const whitelist = await MockWhitelistModule.new({ from: owner }) - - await addressBook.setOracle(oracle.address) - await addressBook.setMarginCalculator(calculator.address) - await addressBook.setMarginPool(marginPool.address) - await addressBook.setWhitelist(whitelist.address) - - // referesh controller configuration - await controllerProxy.refreshConfiguration() - assert.equal(await controllerProxy.oracle(), oracle.address, 'Oracle address mismatch after refresh') - assert.equal( - await controllerProxy.calculator(), - calculator.address, - 'Calculator address mismatch after refresh', - ) - assert.equal(await controllerProxy.pool(), marginPool.address, 'Oracle address mismatch after refresh') - assert.equal(await controllerProxy.whitelist(), whitelist.address, 'Oracle address mismatch after refresh') - }) - }) - - describe('Execute an invalid action', () => { - it('Should execute transaction with no state updates', async () => { - const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOptionsVault(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - assert.isAbove(vaultCounter.toNumber(), 0, 'Account owner have no vault') - - const collateralToDeposit = createTokenAmount(10, usdcDecimals) - const actionArgs = [ - { - actionType: ActionType.InvalidAction, - owner: accountOwner1, - secondAddress: accountOwner1, - asset: usdc.address, - vaultId: vaultCounter.toNumber(), - amount: collateralToDeposit, - index: '0', - data: ZERO_ADDR, - }, - ] - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - await expectRevert.unspecified(controllerProxy.operate(actionArgs, { from: accountOwner1 })) - }) - }) - }, -) diff --git a/test/unit-tests/controllerNakedMargin.test.ts b/test/unit-tests/controllerNakedMargin.test.ts index 7d2aeabe7..4e443906a 100644 --- a/test/unit-tests/controllerNakedMargin.test.ts +++ b/test/unit-tests/controllerNakedMargin.test.ts @@ -4,7 +4,6 @@ import { MockOracleInstance, MockWhitelistModuleInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, ControllerInstance, AddressBookInstance, OwnedUpgradeabilityProxyInstance, @@ -30,7 +29,6 @@ const MarginCalculator = artifacts.require('MarginCalculator.sol') const MockWhitelistModule = artifacts.require('MockWhitelistModule.sol') const AddressBook = artifacts.require('AddressBook.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') @@ -63,8 +61,6 @@ contract('Controller: naked margin', ([owner, accountOwner1, liquidator, random] let calculator: MarginCalculatorInstance // margin pool module let marginPool: MarginPoolInstance - // margin pool module v2 - let borrowableMarginPool: BorrowableMarginPoolInstance // whitelist module mock let whitelist: MockWhitelistModuleInstance // addressbook module mock @@ -109,16 +105,10 @@ contract('Controller: naked margin', ([owner, accountOwner1, liquidator, random] calculator = await MarginCalculator.new(oracle.address) // margin pool deployment marginPool = await MarginPool.new(addressBook.address) - // margin pool v2 deployment - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // whitelist module whitelist = await MockWhitelistModule.new() // set margin pool in addressbook await addressBook.setMarginPool(marginPool.address) - // set borrowable margin pool in addressbook - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: owner, - }) // set calculator in addressbook await addressBook.setMarginCalculator(calculator.address) // set oracle in AddressBook @@ -198,10 +188,6 @@ contract('Controller: naked margin', ([owner, accountOwner1, liquidator, random] // open position const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOTokenBuyer(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const vaultType = web3.eth.abi.encodeParameter('uint256', 1) // const collateralAmount = createTokenAmount(shortStrike, usdcDecimals) const collateralAmount = await calculator.getNakedMarginRequired( @@ -248,7 +234,7 @@ contract('Controller: naked margin', ([owner, accountOwner1, liquidator, random] data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, collateralAmount.toString(), { from: accountOwner1 }) + await usdc.approve(marginPool.address, collateralAmount.toString(), { from: accountOwner1 }) await controllerProxy.operate(mintArgs, { from: accountOwner1 }) const nakedMarginPool = new BigNumber(await controllerProxy.getNakedPoolBalance(usdc.address)) @@ -318,10 +304,6 @@ contract('Controller: naked margin', ([owner, accountOwner1, liquidator, random] // open position vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOTokenBuyer(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const vaultType = web3.eth.abi.encodeParameter('uint256', 1) requiredMargin = new BigNumber( await calculator.getNakedMarginRequired( @@ -372,7 +354,7 @@ contract('Controller: naked margin', ([owner, accountOwner1, liquidator, random] const nakedMarginPoolBefore = new BigNumber(await controllerProxy.getNakedPoolBalance(usdc.address)) - await usdc.approve(finalMarginPool, requiredMargin.toString(), { from: accountOwner1 }) + await usdc.approve(marginPool.address, requiredMargin.toString(), { from: accountOwner1 }) await controllerProxy.operate(mintArgs, { from: accountOwner1 }) const nakedMarginPoolAfter = new BigNumber(await controllerProxy.getNakedPoolBalance(usdc.address)) @@ -538,10 +520,6 @@ contract('Controller: naked margin', ([owner, accountOwner1, liquidator, random] // open position vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOTokenBuyer(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const vaultType = web3.eth.abi.encodeParameter('uint256', 1) requiredMargin = new BigNumber( await calculator.getNakedMarginRequired( @@ -592,7 +570,7 @@ contract('Controller: naked margin', ([owner, accountOwner1, liquidator, random] const nakedMarginPoolBefore = new BigNumber(await controllerProxy.getNakedPoolBalance(weth.address)) - await weth.approve(finalMarginPool, requiredMargin.toString(), { from: accountOwner1 }) + await weth.approve(marginPool.address, requiredMargin.toString(), { from: accountOwner1 }) await controllerProxy.operate(mintArgs, { from: accountOwner1 }) const nakedMarginPoolAfter = new BigNumber(await controllerProxy.getNakedPoolBalance(weth.address)) @@ -759,10 +737,6 @@ contract('Controller: naked margin', ([owner, accountOwner1, liquidator, random] // open position vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOTokenBuyer(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const vaultType = web3.eth.abi.encodeParameter('uint256', 1) requiredMargin = new BigNumber( await calculator.getNakedMarginRequired( @@ -810,7 +784,7 @@ contract('Controller: naked margin', ([owner, accountOwner1, liquidator, random] data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, requiredMargin.toString(), { from: accountOwner1 }) + await usdc.approve(marginPool.address, requiredMargin.toString(), { from: accountOwner1 }) await controllerProxy.operate(mintArgs, { from: accountOwner1 }) const latestVaultUpdateTimestamp = new BigNumber( @@ -1003,10 +977,6 @@ contract('Controller: naked margin', ([owner, accountOwner1, liquidator, random] it('should revert depositing collateral in vault that that hit naked cap', async () => { const vaultType = web3.eth.abi.encodeParameter('uint256', 1) const vaultCounter = new BigNumber(await controllerProxy.getAccountVaultCounter(accountOwner1)).plus(1) - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOTokenBuyer(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - const capAmount = new BigNumber(await controllerProxy.getNakedCap(usdc.address)) const mintArgs = [ @@ -1031,7 +1001,7 @@ contract('Controller: naked margin', ([owner, accountOwner1, liquidator, random] data: ZERO_ADDR, }, ] - await usdc.approve(finalMarginPool, capAmount.toString(), { from: accountOwner1 }) + await usdc.approve(marginPool.address, capAmount.toString(), { from: accountOwner1 }) await expectRevert(controllerProxy.operate(mintArgs, { from: accountOwner1 }), 'C37') }) }) diff --git a/test/unit-tests/payableProxyController.test.ts b/test/unit-tests/payableProxyController.test.ts index 2afe1bb70..9640773c2 100644 --- a/test/unit-tests/payableProxyController.test.ts +++ b/test/unit-tests/payableProxyController.test.ts @@ -6,7 +6,6 @@ import { MockWhitelistModuleInstance, MarginCalculatorInstance, MarginPoolInstance, - BorrowableMarginPoolInstance, ControllerInstance, AddressBookInstance, OwnedUpgradeabilityProxyInstance, @@ -27,7 +26,6 @@ const MarginCalculator = artifacts.require('MarginCalculator.sol') const MockWhitelistModule = artifacts.require('MockWhitelistModule.sol') const AddressBook = artifacts.require('AddressBook.sol') const MarginPool = artifacts.require('MarginPool.sol') -const BorrowableMarginPool = artifacts.require('BorrowableMarginPool.sol') const Controller = artifacts.require('Controller.sol') const MarginVault = artifacts.require('MarginVault.sol') const CalleeAllowanceTester = artifacts.require('CalleeAllowanceTester.sol') @@ -61,8 +59,6 @@ contract('PayableProxyController', ([owner, accountOwner1, holder1, random]) => let calculator: MarginCalculatorInstance // margin pool module let marginPool: MarginPoolInstance - // margin pool v2 module - let borrowableMarginPool: BorrowableMarginPoolInstance // whitelist module mock let whitelist: MockWhitelistModuleInstance // addressbook module mock @@ -88,18 +84,12 @@ contract('PayableProxyController', ([owner, accountOwner1, holder1, random]) => calculator = await MarginCalculator.new(oracle.address) // margin pool deployment marginPool = await MarginPool.new(addressBook.address) - // margin pool v2 deployment - borrowableMarginPool = await BorrowableMarginPool.new(addressBook.address) // whitelist module whitelist = await MockWhitelistModule.new() // callee allowance tester testerCallee = await CalleeAllowanceTester.new(weth.address) // set margin pool in addressbook await addressBook.setMarginPool(marginPool.address) - // set borrowable margin pool in addressbook - await addressBook.setAddress(web3.utils.soliditySha3('BORROWABLE_POOL'), borrowableMarginPool.address, { - from: owner, - }) // set calculator in addressbook await addressBook.setMarginCalculator(calculator.address) // set oracle in AddressBook @@ -162,18 +152,14 @@ contract('PayableProxyController', ([owner, accountOwner1, holder1, random]) => }, ] - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOTokenBuyer(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - const marginPoolBalanceBefore = new BigNumber(await weth.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await weth.balanceOf(marginPool.address)) await payableProxyController.operate(actionArgs, accountOwner1, { from: accountOwner1, value: collateralToDeposit.toString(), }) - const marginPoolBalanceAfter = new BigNumber(await weth.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await weth.balanceOf(marginPool.address)) const vaultAfter = (await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter))[0] assert.equal( @@ -222,18 +208,14 @@ contract('PayableProxyController', ([owner, accountOwner1, holder1, random]) => }, ] - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOTokenBuyer(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - const marginPoolBalanceBefore = new BigNumber(await weth.balanceOf(finalMarginPool)) + const marginPoolBalanceBefore = new BigNumber(await weth.balanceOf(marginPool.address)) await payableProxyController.operate(actionArgs, accountOwner1, { from: accountOwner1, value: ethToSend.toString(), }) - const marginPoolBalanceAfter = new BigNumber(await weth.balanceOf(finalMarginPool)) + const marginPoolBalanceAfter = new BigNumber(await weth.balanceOf(marginPool.address)) const vaultAfter = (await controllerProxy.getVaultWithDetails(accountOwner1, vaultCounter))[0] assert.equal( @@ -446,13 +428,7 @@ contract('PayableProxyController', ([owner, accountOwner1, holder1, random]) => data: ZERO_ADDR, }, ] - - const finalMarginPool = (await borrowableMarginPool.isWhitelistedOTokenBuyer(accountOwner1)) - ? borrowableMarginPool.address - : marginPool.address - - await usdc.approve(finalMarginPool, collateralToDeposit, { from: accountOwner1 }) - + await usdc.approve(marginPool.address, collateralToDeposit, { from: accountOwner1 }) await payableProxyController.operate(actionArgs, accountOwner1, { from: accountOwner1 }) // transfer minted short otoken to hodler` await shortOtoken.transfer(holder1, amountToMint.toString(), { from: accountOwner1 })