/ test / finance / OptionsExchange / TestCoveredLiquidation.t.sol
TestCoveredLiquidation.t.sol
  1  pragma solidity >=0.6.0;
  2  pragma experimental ABIEncoderV2;
  3  
  4  import "truffle/Assert.sol";
  5  import "../../../contracts/finance/OptionToken.sol";
  6  import "../../../contracts/utils/MoreMath.sol";
  7  import "./Base.t.sol";
  8  
  9  contract TestCoveredLiquidation is Base {
 10      
 11      function testLiquidationBeforeAllowed() public {
 12          underlying.reset(address(this));
 13          underlying.issue(address(this), 3 * underlyingBase);
 14          address _tk = writeCovered(3, ethInitialPrice, 10 days, address(alice));
 15  
 16          OptionToken tk = OptionToken(_tk);
 17  
 18          //tk.transfer(address(alice), 2 * volumeBase);
 19  
 20          Assert.equal(1 * volumeBase, tk.balanceOf(address(this)), "writer tk balance");
 21          Assert.equal(2 * volumeBase, tk.balanceOf(address(alice)), "alice tk balance");
 22              
 23          (bool success,) = address(alice).call(
 24              abi.encodePacked(
 25                  alice.liquidateOptions.selector,
 26                  abi.encode(_tk, address(alice))
 27              )
 28          );
 29          
 30          Assert.isFalse(success, "liquidate should fail");
 31      }
 32  
 33      function testLiquidationAtMaturityOTM() public {
 34          
 35          underlying.reset(address(this));
 36          underlying.issue(address(this), 2 * underlyingBase);
 37          
 38          int step = 40e18;
 39  
 40          address _tk = writeCovered(2, ethInitialPrice, 10 days, address(alice));
 41  
 42          OptionToken tk = OptionToken(_tk);
 43          
 44  
 45          feed.setPrice(ethInitialPrice - step);
 46          time.setTimeOffset(10 days);
 47  
 48          uint b0 = underlying.balanceOf(address(this));
 49          Assert.equal(b0, 0, "underlying before liquidation");
 50  
 51          (bool success,) = address(this).call(
 52              abi.encodePacked(
 53                  collateralManager.liquidateOptions.selector,
 54                  abi.encode(_tk, address(this))
 55              )
 56          );
 57  
 58          uint b1 = underlying.balanceOf(address(this));
 59          Assert.equal(b1, 2 * underlyingBase, "underlying after liquidation");
 60  
 61          Assert.equal(exchange.calcCollateral(address(this), true), 0, "writer final collateral");
 62          Assert.equal(alice.calcCollateral(), 0, "alice final collateral");
 63  
 64          Assert.equal(exchange.calcSurplus(address(this)), 0, "writer final surplus");
 65          Assert.equal(alice.calcSurplus(), 0, "alice final surplus");
 66      }
 67  
 68      function testLiquidateMultipleITM() public {
 69          
 70          underlying.reset(address(this));
 71          underlying.issue(address(this), 4 * underlyingBase);
 72  
 73          settings.setSwapRouterInfo(router, address(erc20));
 74          settings.setSwapRouterTolerance(105e4, 1e6);
 75          
 76          int step = 40e18;
 77  
 78          address _tk100 = writeCovered(2, ethInitialPrice, 100 days, address(alice));
 79          address _tk200 = writeCovered(2, ethInitialPrice, 200 days, address(alice));
 80  
 81          OptionToken tk100 = OptionToken(_tk100);
 82          OptionToken tk200 = OptionToken(_tk200);
 83          
 84  
 85          feed.setPrice(ethInitialPrice + step);
 86  
 87          time.setTimeOffset(100 days);
 88          (bool success,) = address(this).call(
 89              abi.encodePacked(
 90                  collateralManager.liquidateOptions.selector,
 91                  abi.encode(_tk100, address(this))
 92              )
 93          );
 94          
 95          time.setTimeOffset(200 days);
 96          (bool success1,) = address(this).call(
 97              abi.encodePacked(
 98                  collateralManager.liquidateOptions.selector,
 99                  abi.encode(_tk200, address(this))
100              )
101          );
102      }
103  
104      function writeCovered(
105          uint volume,
106          int strike, 
107          uint timeToMaturity,
108          address trader
109      )
110          public
111          returns (address _tk)
112      {
113          IERC20(
114              UnderlyingFeed(feed).getUnderlyingAddr()
115          ).approve(address(exchange), volume * volumeBase);
116  
117          _tk = exchange.createSymbol(
118              address(feed),
119              IOptionsExchange.OptionType.CALL,
120              uint(strike), 
121              time.getNow() + timeToMaturity
122          );
123  
124          addSymbol(uint(strike), time.getNow() + timeToMaturity);
125  
126          IOptionsExchange.OpenExposureInputs memory oEi;
127  
128          oEi.symbols = new string[](1);
129          oEi.volume = new uint[](1);
130          oEi.isShort = new bool[](1);
131          oEi.isCovered = new bool[](1);
132          oEi.poolAddrs = new address[](1);
133          oEi.paymentTokens = new address[](1);
134  
135  
136          oEi.symbols[0] = IOptionToken(_tk).symbol();
137          oEi.volume[0] = volume * volumeBase;
138          oEi.isShort[0] = true;
139          oEi.poolAddrs[0] = pool;//poolAddr;
140          oEi.isCovered[0] = true;
141          //oEi.paymentTokens[0] = address(0); //exploiting default to save gas
142  
143          (bool success,) = address(this).call(
144              abi.encodePacked(
145                  exchange.openExposure.selector,
146                  abi.encode(oEi, trader)
147              )
148          );
149  
150          Assert.equal(success,true, "covered option written");
151      }
152  }